source: git/factory/facMul.cc @ 03c742

spielwiese
Last change on this file since 03c742 was 03c742, checked in by Hans Schoenemann <hannes@…>, 4 years ago
factory: BuildIrred, FLINT/NTL seperation
  • Property mode set to 100644
File size: 92.5 KB
Line 
1/*****************************************************************************\
2 * Computer Algebra System SINGULAR
3\*****************************************************************************/
4/** @file facMul.cc
5 *
6 * This file implements functions for fast multiplication and division with
7 * remainder.
8 *
9 * Nomenclature rules: kronSub* -> plain Kronecker substitution
10 *                     reverseSubst* -> reverse Kronecker substitution
11 *                     kronSubRecipro* -> reciprocal Kronecker substitution as
12 *                                        described in D. Harvey "Faster
13 *                                        polynomial multiplication via
14 *                                        multipoint Kronecker substitution"
15 *
16 * @author Martin Lee
17 *
18 **/
19/*****************************************************************************/
20
21#include "debug.h"
22
23#include "config.h"
24
25
26#include "canonicalform.h"
27#include "facMul.h"
28#include "cf_util.h"
29#include "cf_iter.h"
30#include "cf_algorithm.h"
31#include "templates/ftmpl_functions.h"
32
33#ifdef HAVE_NTL
34#include <NTL/lzz_pEX.h>
35#include "NTLconvert.h"
36#endif
37
38#ifdef HAVE_FLINT
39#include "FLINTconvert.h"
40#endif
41
42// univariate polys
43#if defined(HAVE_NTL) || defined(HAVE_FLINT)
44
45#ifdef HAVE_FLINT
46void kronSubQa (fmpz_poly_t result, const CanonicalForm& A, int d)
47{
48  int degAy= degree (A);
49  fmpz_poly_init2 (result, d*(degAy + 1));
50  _fmpz_poly_set_length (result, d*(degAy + 1));
51  CFIterator j;
52  for (CFIterator i= A; i.hasTerms(); i++)
53  {
54    if (i.coeff().inBaseDomain())
55      convertCF2Fmpz (fmpz_poly_get_coeff_ptr (result, i.exp()*d), i.coeff());
56    else
57      for (j= i.coeff(); j.hasTerms(); j++)
58        convertCF2Fmpz (fmpz_poly_get_coeff_ptr (result, i.exp()*d+j.exp()),
59                        j.coeff());
60  }
61  _fmpz_poly_normalise(result);
62}
63
64
65CanonicalForm
66reverseSubstQa (const fmpz_poly_t F, int d, const Variable& x,
67                const Variable& alpha, const CanonicalForm& den)
68{
69  CanonicalForm result= 0;
70  int i= 0;
71  int degf= fmpz_poly_degree (F);
72  int k= 0;
73  int degfSubK;
74  int repLength;
75  fmpq_poly_t buf;
76  fmpq_poly_t mipo;
77  convertFacCF2Fmpq_poly_t (mipo, getMipo(alpha));
78  while (degf >= k)
79  {
80    degfSubK= degf - k;
81    if (degfSubK >= d)
82      repLength= d;
83    else
84      repLength= degfSubK + 1;
85
86    fmpq_poly_init2 (buf, repLength);
87    _fmpq_poly_set_length (buf, repLength);
88    _fmpz_vec_set (buf->coeffs, F->coeffs + k, repLength);
89    _fmpq_poly_normalise (buf);
90    fmpq_poly_rem (buf, buf, mipo);
91
92    result += convertFmpq_poly_t2FacCF (buf, alpha)*power (x, i);
93    fmpq_poly_clear (buf);
94    i++;
95    k= d*i;
96  }
97  fmpq_poly_clear (mipo);
98  result /= den;
99  return result;
100}
101
102CanonicalForm
103mulFLINTQa (const CanonicalForm& F, const CanonicalForm& G,
104            const Variable& alpha)
105{
106  CanonicalForm A= F;
107  CanonicalForm B= G;
108
109  CanonicalForm denA= bCommonDen (A);
110  CanonicalForm denB= bCommonDen (B);
111
112  A *= denA;
113  B *= denB;
114  int degAa= degree (A, alpha);
115  int degBa= degree (B, alpha);
116  int d= degAa + 1 + degBa;
117
118  fmpz_poly_t FLINTA,FLINTB;
119  kronSubQa (FLINTA, A, d);
120  kronSubQa (FLINTB, B, d);
121
122  fmpz_poly_mul (FLINTA, FLINTA, FLINTB);
123
124  denA *= denB;
125  A= reverseSubstQa (FLINTA, d, F.mvar(), alpha, denA);
126
127  fmpz_poly_clear (FLINTA);
128  fmpz_poly_clear (FLINTB);
129  return A;
130}
131
132CanonicalForm
133mulFLINTQ (const CanonicalForm& F, const CanonicalForm& G)
134{
135  CanonicalForm A= F;
136  CanonicalForm B= G;
137
138  CanonicalForm denA= bCommonDen (A);
139  CanonicalForm denB= bCommonDen (B);
140
141  A *= denA;
142  B *= denB;
143  fmpz_poly_t FLINTA,FLINTB;
144  convertFacCF2Fmpz_poly_t (FLINTA, A);
145  convertFacCF2Fmpz_poly_t (FLINTB, B);
146  fmpz_poly_mul (FLINTA, FLINTA, FLINTB);
147  denA *= denB;
148  A= convertFmpz_poly_t2FacCF (FLINTA, F.mvar());
149  A /= denA;
150  fmpz_poly_clear (FLINTA);
151  fmpz_poly_clear (FLINTB);
152
153  return A;
154}
155
156/*CanonicalForm
157mulFLINTQ2 (const CanonicalForm& F, const CanonicalForm& G)
158{
159  CanonicalForm A= F;
160  CanonicalForm B= G;
161
162  fmpq_poly_t FLINTA,FLINTB;
163  convertFacCF2Fmpq_poly_t (FLINTA, A);
164  convertFacCF2Fmpq_poly_t (FLINTB, B);
165
166  fmpq_poly_mul (FLINTA, FLINTA, FLINTB);
167  A= convertFmpq_poly_t2FacCF (FLINTA, F.mvar());
168  fmpq_poly_clear (FLINTA);
169  fmpq_poly_clear (FLINTB);
170  return A;
171}*/
172
173CanonicalForm
174divFLINTQ (const CanonicalForm& F, const CanonicalForm& G)
175{
176  CanonicalForm A= F;
177  CanonicalForm B= G;
178
179  fmpq_poly_t FLINTA,FLINTB;
180  convertFacCF2Fmpq_poly_t (FLINTA, A);
181  convertFacCF2Fmpq_poly_t (FLINTB, B);
182
183  fmpq_poly_div (FLINTA, FLINTA, FLINTB);
184  A= convertFmpq_poly_t2FacCF (FLINTA, F.mvar());
185
186  fmpq_poly_clear (FLINTA);
187  fmpq_poly_clear (FLINTB);
188  return A;
189}
190
191CanonicalForm
192modFLINTQ (const CanonicalForm& F, const CanonicalForm& G)
193{
194  CanonicalForm A= F;
195  CanonicalForm B= G;
196
197  fmpq_poly_t FLINTA,FLINTB;
198  convertFacCF2Fmpq_poly_t (FLINTA, A);
199  convertFacCF2Fmpq_poly_t (FLINTB, B);
200
201  fmpq_poly_rem (FLINTA, FLINTA, FLINTB);
202  A= convertFmpq_poly_t2FacCF (FLINTA, F.mvar());
203
204  fmpq_poly_clear (FLINTA);
205  fmpq_poly_clear (FLINTB);
206  return A;
207}
208
209CanonicalForm
210mulFLINTQaTrunc (const CanonicalForm& F, const CanonicalForm& G,
211                 const Variable& alpha, int m)
212{
213  CanonicalForm A= F;
214  CanonicalForm B= G;
215
216  CanonicalForm denA= bCommonDen (A);
217  CanonicalForm denB= bCommonDen (B);
218
219  A *= denA;
220  B *= denB;
221
222  int degAa= degree (A, alpha);
223  int degBa= degree (B, alpha);
224  int d= degAa + 1 + degBa;
225
226  fmpz_poly_t FLINTA,FLINTB;
227  kronSubQa (FLINTA, A, d);
228  kronSubQa (FLINTB, B, d);
229
230  int k= d*m;
231  fmpz_poly_mullow (FLINTA, FLINTA, FLINTB, k);
232
233  denA *= denB;
234  A= reverseSubstQa (FLINTA, d, F.mvar(), alpha, denA);
235  fmpz_poly_clear (FLINTA);
236  fmpz_poly_clear (FLINTB);
237  return A;
238}
239
240CanonicalForm
241mulFLINTQTrunc (const CanonicalForm& F, const CanonicalForm& G, int m)
242{
243  if (F.inCoeffDomain() && G.inCoeffDomain())
244    return F*G;
245  if (F.inCoeffDomain())
246    return mod (F*G, power (G.mvar(), m));
247  if (G.inCoeffDomain())
248    return mod (F*G, power (F.mvar(), m));
249  Variable alpha;
250  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
251    return mulFLINTQaTrunc (F, G, alpha, m);
252
253  CanonicalForm A= F;
254  CanonicalForm B= G;
255
256  CanonicalForm denA= bCommonDen (A);
257  CanonicalForm denB= bCommonDen (B);
258
259  A *= denA;
260  B *= denB;
261  fmpz_poly_t FLINTA,FLINTB;
262  convertFacCF2Fmpz_poly_t (FLINTA, A);
263  convertFacCF2Fmpz_poly_t (FLINTB, B);
264  fmpz_poly_mullow (FLINTA, FLINTA, FLINTB, m);
265  denA *= denB;
266  A= convertFmpz_poly_t2FacCF (FLINTA, F.mvar());
267  A /= denA;
268  fmpz_poly_clear (FLINTA);
269  fmpz_poly_clear (FLINTB);
270
271  return A;
272}
273
274CanonicalForm uniReverse (const CanonicalForm& F, int d, const Variable& x)
275{
276  if (d == 0)
277    return F;
278  if (F.inCoeffDomain())
279    return F*power (x,d);
280  CanonicalForm result= 0;
281  CFIterator i= F;
282  while (d - i.exp() < 0)
283    i++;
284
285  for (; i.hasTerms() && (d - i.exp() >= 0); i++)
286    result += i.coeff()*power (x, d - i.exp());
287  return result;
288}
289
290CanonicalForm
291newtonInverse (const CanonicalForm& F, const int n, const Variable& x)
292{
293  int l= ilog2(n);
294
295  CanonicalForm g;
296  if (F.inCoeffDomain())
297    g= F;
298  else
299    g= F [0];
300
301  if (!F.inCoeffDomain())
302    ASSERT (F.mvar() == x, "main variable of F and x differ");
303  ASSERT (!g.isZero(), "expected a unit");
304
305  if (!g.isOne())
306    g = 1/g;
307  CanonicalForm result;
308  int exp= 0;
309  if (n & 1)
310  {
311    result= g;
312    exp= 1;
313  }
314  CanonicalForm h;
315
316  for (int i= 1; i <= l; i++)
317  {
318    h= mulNTL (g, mod (F, power (x, (1 << i))));
319    h= mod (h, power (x, (1 << i)) - 1);
320    h= div (h, power (x, (1 << (i - 1))));
321    g -= power (x, (1 << (i - 1)))*
322         mulFLINTQTrunc (g, h, 1 << (i-1));
323
324    if (n & (1 << i))
325    {
326      if (exp)
327      {
328        h= mulNTL (result, mod (F, power (x, exp + (1 << i))));
329        h= mod (h, power (x, exp + (1 << i)) - 1);
330        h= div (h, power (x, exp));
331        result -= power(x, exp)*mulFLINTQTrunc (g, h, 1 << i);
332        exp += (1 << i);
333      }
334      else
335      {
336        exp= (1 << i);
337        result= g;
338      }
339    }
340  }
341
342  return result;
343}
344
345void
346newtonDivrem (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
347              CanonicalForm& R)
348{
349  ASSERT (F.level() == G.level(), "F and G have different level");
350  CanonicalForm A= F;
351  CanonicalForm B= G;
352  Variable x= A.mvar();
353  int degA= degree (A);
354  int degB= degree (B);
355  int m= degA - degB;
356
357  if (m < 0)
358  {
359    R= A;
360    Q= 0;
361    return;
362  }
363
364  if (degB <= 1)
365    divrem (A, B, Q, R);
366  else
367  {
368    R= uniReverse (A, degA, x);
369
370    CanonicalForm revB= uniReverse (B, degB, x);
371    revB= newtonInverse (revB, m + 1, x);
372    Q= mulFLINTQTrunc (R, revB, m + 1);
373    Q= uniReverse (Q, m, x);
374
375    R= A - mulNTL (Q, B);
376  }
377}
378
379void
380newtonDiv (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q)
381{
382  ASSERT (F.level() == G.level(), "F and G have different level");
383  CanonicalForm A= F;
384  CanonicalForm B= G;
385  Variable x= A.mvar();
386  int degA= degree (A);
387  int degB= degree (B);
388  int m= degA - degB;
389
390  if (m < 0)
391  {
392    Q= 0;
393    return;
394  }
395
396  if (degB <= 1)
397    Q= div (A, B);
398  else
399  {
400    CanonicalForm R= uniReverse (A, degA, x);
401    CanonicalForm revB= uniReverse (B, degB, x);
402    revB= newtonInverse (revB, m + 1, x);
403    Q= mulFLINTQTrunc (R, revB, m + 1);
404    Q= uniReverse (Q, m, x);
405  }
406}
407
408#endif
409
410CanonicalForm
411mulNTL (const CanonicalForm& F, const CanonicalForm& G, const modpk& b)
412{
413  if (CFFactory::gettype() == GaloisFieldDomain)
414    return F*G;
415  if (getCharacteristic() == 0)
416  {
417    Variable alpha;
418    if ((!F.inCoeffDomain() && !G.inCoeffDomain()) &&
419        (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha)))
420    {
421      if (b.getp() != 0)
422      {
423        CanonicalForm mipo= getMipo (alpha);
424        bool is_rat= isOn (SW_RATIONAL);
425        if (!is_rat)
426          On (SW_RATIONAL);
427        mipo *=bCommonDen (mipo);
428        if (!is_rat)
429          Off (SW_RATIONAL);
430#if (HAVE_FLINT && __FLINT_RELEASE >= 20400)
431        fmpz_t FLINTp;
432        fmpz_mod_poly_t FLINTmipo;
433        fq_ctx_t fq_con;
434        fq_poly_t FLINTF, FLINTG;
435
436        fmpz_init (FLINTp);
437
438        convertCF2Fmpz (FLINTp, b.getpk());
439
440        convertFacCF2Fmpz_mod_poly_t (FLINTmipo, mipo, FLINTp);
441
442        fq_ctx_init_modulus (fq_con, FLINTmipo, "Z");
443
444        convertFacCF2Fq_poly_t (FLINTF, F, fq_con);
445        convertFacCF2Fq_poly_t (FLINTG, G, fq_con);
446
447        fq_poly_mul (FLINTF, FLINTF, FLINTG, fq_con);
448
449        CanonicalForm result= convertFq_poly_t2FacCF (FLINTF, F.mvar(),
450                                                      alpha, fq_con);
451
452        fmpz_clear (FLINTp);
453        fmpz_mod_poly_clear (FLINTmipo);
454        fq_poly_clear (FLINTF, fq_con);
455        fq_poly_clear (FLINTG, fq_con);
456        fq_ctx_clear (fq_con);
457        return b (result);
458#endif
459#ifdef HAVE_NTL
460        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
461        ZZ_pX NTLmipo= to_ZZ_pX (convertFacCF2NTLZZX (mipo));
462        ZZ_pE::init (NTLmipo);
463        ZZ_pEX NTLg= convertFacCF2NTLZZ_pEX (G, NTLmipo);
464        ZZ_pEX NTLf= convertFacCF2NTLZZ_pEX (F, NTLmipo);
465        mul (NTLf, NTLf, NTLg);
466
467        return b (convertNTLZZ_pEX2CF (NTLf, F.mvar(), alpha));
468#endif
469      }
470#ifdef HAVE_FLINT
471      CanonicalForm result= mulFLINTQa (F, G, alpha);
472      return result;
473#else
474      return F*G;
475#endif
476    }
477    else if (!F.inCoeffDomain() && !G.inCoeffDomain())
478    {
479#ifdef HAVE_FLINT
480      if (b.getp() != 0)
481      {
482        fmpz_t FLINTpk;
483        fmpz_init (FLINTpk);
484        convertCF2Fmpz (FLINTpk, b.getpk());
485        fmpz_mod_poly_t FLINTF, FLINTG;
486        convertFacCF2Fmpz_mod_poly_t (FLINTF, F, FLINTpk);
487        convertFacCF2Fmpz_mod_poly_t (FLINTG, G, FLINTpk);
488        fmpz_mod_poly_mul (FLINTF, FLINTF, FLINTG);
489        CanonicalForm result= convertFmpz_mod_poly_t2FacCF (FLINTF, F.mvar(),b);
490        fmpz_mod_poly_clear (FLINTG);
491        fmpz_mod_poly_clear (FLINTF);
492        fmpz_clear (FLINTpk);
493        return result;
494      }
495      return mulFLINTQ (F, G);
496#endif
497#ifdef HAVE_NTL
498      if (b.getp() != 0)
499      {
500        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
501        ZZX ZZf= convertFacCF2NTLZZX (F);
502        ZZX ZZg= convertFacCF2NTLZZX (G);
503        ZZ_pX NTLf= to_ZZ_pX (ZZf);
504        ZZ_pX NTLg= to_ZZ_pX (ZZg);
505        mul (NTLf, NTLf, NTLg);
506        return b (convertNTLZZX2CF (to_ZZX (NTLf), F.mvar()));
507      }
508      return F*G;
509#endif
510    }
511    if (b.getp() != 0)
512    {
513      if (!F.inBaseDomain() && !G.inBaseDomain())
514      {
515        if (hasFirstAlgVar (G, alpha) || hasFirstAlgVar (F, alpha))
516        {
517#if (HAVE_FLINT && __FLINT_RELEASE >= 20400)
518          fmpz_t FLINTp;
519          fmpz_mod_poly_t FLINTmipo;
520          fq_ctx_t fq_con;
521
522          fmpz_init (FLINTp);
523          convertCF2Fmpz (FLINTp, b.getpk());
524
525          convertFacCF2Fmpz_mod_poly_t (FLINTmipo, getMipo (alpha), FLINTp);
526
527          fq_ctx_init_modulus (fq_con, FLINTmipo, "Z");
528
529          CanonicalForm result;
530
531          if (F.inCoeffDomain() && !G.inCoeffDomain())
532          {
533            fq_poly_t FLINTG;
534            fmpz_poly_t FLINTF;
535            convertFacCF2Fmpz_poly_t (FLINTF, F);
536            convertFacCF2Fq_poly_t (FLINTG, G, fq_con);
537
538            fq_poly_scalar_mul_fq (FLINTG, FLINTG, FLINTF, fq_con);
539
540            result= convertFq_poly_t2FacCF (FLINTG, G.mvar(), alpha, fq_con);
541            fmpz_poly_clear (FLINTF);
542            fq_poly_clear (FLINTG, fq_con);
543          }
544          else if (!F.inCoeffDomain() && G.inCoeffDomain())
545          {
546            fq_poly_t FLINTF;
547            fmpz_poly_t FLINTG;
548
549            convertFacCF2Fmpz_poly_t (FLINTG, G);
550            convertFacCF2Fq_poly_t (FLINTF, F, fq_con);
551
552            fq_poly_scalar_mul_fq (FLINTF, FLINTF, FLINTG, fq_con);
553
554            result= convertFq_poly_t2FacCF (FLINTF, F.mvar(), alpha, fq_con);
555            fmpz_poly_clear (FLINTG);
556            fq_poly_clear (FLINTF, fq_con);
557          }
558          else
559          {
560            fq_t FLINTF, FLINTG;
561
562            convertFacCF2Fq_t (FLINTF, F, fq_con);
563            convertFacCF2Fq_t (FLINTG, G, fq_con);
564
565            fq_mul (FLINTF, FLINTF, FLINTG, fq_con);
566
567            result= convertFq_t2FacCF (FLINTF, alpha);
568            fq_clear (FLINTF, fq_con);
569            fq_clear (FLINTG, fq_con);
570          }
571
572          fmpz_clear (FLINTp);
573          fmpz_mod_poly_clear (FLINTmipo);
574          fq_ctx_clear (fq_con);
575
576          return b (result);
577#endif
578#ifdef HAVE_NTL
579          ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
580          ZZ_pX NTLmipo= to_ZZ_pX (convertFacCF2NTLZZX (getMipo (alpha)));
581          ZZ_pE::init (NTLmipo);
582
583          if (F.inCoeffDomain() && !G.inCoeffDomain())
584          {
585            ZZ_pEX NTLg= convertFacCF2NTLZZ_pEX (G, NTLmipo);
586            ZZ_pX NTLf= convertFacCF2NTLZZpX (F);
587            mul (NTLg, to_ZZ_pE (NTLf), NTLg);
588            return b (convertNTLZZ_pEX2CF (NTLg, G.mvar(), alpha));
589          }
590          else if (!F.inCoeffDomain() && G.inCoeffDomain())
591          {
592            ZZ_pX NTLg= convertFacCF2NTLZZpX (G);
593            ZZ_pEX NTLf= convertFacCF2NTLZZ_pEX (F, NTLmipo);
594            mul (NTLf, NTLf, to_ZZ_pE (NTLg));
595            return b (convertNTLZZ_pEX2CF (NTLf, F.mvar(), alpha));
596          }
597          else
598          {
599            ZZ_pX NTLg= convertFacCF2NTLZZpX (G);
600            ZZ_pX NTLf= convertFacCF2NTLZZpX (F);
601            ZZ_pE result;
602            mul (result, to_ZZ_pE (NTLg), to_ZZ_pE (NTLf));
603            return b (convertNTLZZpX2CF (rep (result), alpha));
604          }
605#endif
606        }
607      }
608      return b (F*G);
609    }
610    return F*G;
611  }
612  else if (F.inCoeffDomain() || G.inCoeffDomain())
613    return F*G;
614  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
615  ASSERT (F.level() == G.level(), "expected polys of same level");
616#ifdef HAVE_NTL
617#if (!defined(HAVE_FLINT) ||  __FLINT_RELEASE < 20400)
618  if (fac_NTL_char != getCharacteristic())
619  {
620    fac_NTL_char= getCharacteristic();
621    zz_p::init (getCharacteristic());
622  }
623#endif
624#endif
625  Variable alpha;
626  CanonicalForm result;
627  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
628  {
629    if (!getReduce (alpha))
630    {
631      result= 0;
632      for (CFIterator i= F; i.hasTerms(); i++)
633        result += i.coeff()*G*power (F.mvar(),i.exp());
634      return result;
635    }
636#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
637    nmod_poly_t FLINTmipo;
638    fq_nmod_ctx_t fq_con;
639
640    nmod_poly_init (FLINTmipo, getCharacteristic());
641    convertFacCF2nmod_poly_t (FLINTmipo, getMipo (alpha));
642
643    fq_nmod_ctx_init_modulus (fq_con, FLINTmipo, "Z");
644
645    fq_nmod_poly_t FLINTF, FLINTG;
646    convertFacCF2Fq_nmod_poly_t (FLINTF, F, fq_con);
647    convertFacCF2Fq_nmod_poly_t (FLINTG, G, fq_con);
648
649    fq_nmod_poly_mul (FLINTF, FLINTF, FLINTG, fq_con);
650
651    result= convertFq_nmod_poly_t2FacCF (FLINTF, F.mvar(), alpha, fq_con);
652
653    fq_nmod_poly_clear (FLINTF, fq_con);
654    fq_nmod_poly_clear (FLINTG, fq_con);
655    nmod_poly_clear (FLINTmipo);
656    fq_nmod_ctx_clear (fq_con);
657    return result;
658#elif defined(AHVE_NTL)
659    zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
660    zz_pE::init (NTLMipo);
661    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
662    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
663    mul (NTLF, NTLF, NTLG);
664    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
665    return result;
666#endif
667  }
668  else
669  {
670#ifdef HAVE_FLINT
671    nmod_poly_t FLINTF, FLINTG;
672    convertFacCF2nmod_poly_t (FLINTF, F);
673    convertFacCF2nmod_poly_t (FLINTG, G);
674    nmod_poly_mul (FLINTF, FLINTF, FLINTG);
675    result= convertnmod_poly_t2FacCF (FLINTF, F.mvar());
676    nmod_poly_clear (FLINTF);
677    nmod_poly_clear (FLINTG);
678    return result;
679#endif
680#ifdef HAVE_NTL
681    zz_pX NTLF= convertFacCF2NTLzzpX (F);
682    zz_pX NTLG= convertFacCF2NTLzzpX (G);
683    mul (NTLF, NTLF, NTLG);
684    return convertNTLzzpX2CF(NTLF, F.mvar());
685#endif
686  }
687  return F*G;
688}
689
690CanonicalForm
691modNTL (const CanonicalForm& F, const CanonicalForm& G, const modpk& b)
692{
693  if (CFFactory::gettype() == GaloisFieldDomain)
694    return mod (F, G);
695  if (F.inCoeffDomain() && G.isUnivariate() && !G.inCoeffDomain())
696  {
697    if (b.getp() != 0)
698      return b(F);
699    return F;
700  }
701  else if (F.inCoeffDomain() && G.inCoeffDomain())
702  {
703    if (b.getp() != 0)
704      return b(F%G);
705    return mod (F, G);
706  }
707  else if (F.isUnivariate() && G.inCoeffDomain())
708  {
709    if (b.getp() != 0)
710      return b(F%G);
711    return mod (F,G);
712  }
713
714  if (getCharacteristic() == 0)
715  {
716    Variable alpha;
717    if (!hasFirstAlgVar (F, alpha) && !hasFirstAlgVar (G, alpha))
718    {
719#ifdef HAVE_FLINT
720      if (b.getp() != 0)
721      {
722        fmpz_t FLINTpk;
723        fmpz_init (FLINTpk);
724        convertCF2Fmpz (FLINTpk, b.getpk());
725        fmpz_mod_poly_t FLINTF, FLINTG;
726        convertFacCF2Fmpz_mod_poly_t (FLINTF, F, FLINTpk);
727        convertFacCF2Fmpz_mod_poly_t (FLINTG, G, FLINTpk);
728        fmpz_mod_poly_divrem (FLINTG, FLINTF, FLINTF, FLINTG);
729        CanonicalForm result= convertFmpz_mod_poly_t2FacCF (FLINTF,F.mvar(),b);
730        fmpz_mod_poly_clear (FLINTG);
731        fmpz_mod_poly_clear (FLINTF);
732        fmpz_clear (FLINTpk);
733        return result;
734      }
735      return modFLINTQ (F, G);
736#else
737      if (b.getp() != 0)
738      {
739        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
740        ZZX ZZf= convertFacCF2NTLZZX (F);
741        ZZX ZZg= convertFacCF2NTLZZX (G);
742        ZZ_pX NTLf= to_ZZ_pX (ZZf);
743        ZZ_pX NTLg= to_ZZ_pX (ZZg);
744        rem (NTLf, NTLf, NTLg);
745        return b (convertNTLZZX2CF (to_ZZX (NTLf), F.mvar()));
746      }
747      return mod (F, G);
748#endif
749    }
750    else
751    {
752      if (b.getp() != 0)
753      {
754#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
755        fmpz_t FLINTp;
756        fmpz_mod_poly_t FLINTmipo;
757        fq_ctx_t fq_con;
758        fq_poly_t FLINTF, FLINTG;
759
760        fmpz_init (FLINTp);
761
762        convertCF2Fmpz (FLINTp, b.getpk());
763
764        convertFacCF2Fmpz_mod_poly_t (FLINTmipo, getMipo (alpha), FLINTp);
765
766        fq_ctx_init_modulus (fq_con, FLINTmipo, "Z");
767
768        convertFacCF2Fq_poly_t (FLINTF, F, fq_con);
769        convertFacCF2Fq_poly_t (FLINTG, G, fq_con);
770
771        fq_poly_rem (FLINTF, FLINTF, FLINTG, fq_con);
772
773        CanonicalForm result= convertFq_poly_t2FacCF (FLINTF, F.mvar(),
774                                                      alpha, fq_con);
775
776        fmpz_clear (FLINTp);
777        fmpz_mod_poly_clear (FLINTmipo);
778        fq_poly_clear (FLINTF, fq_con);
779        fq_poly_clear (FLINTG, fq_con);
780        fq_ctx_clear (fq_con);
781
782        return b(result);
783#else
784        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
785        ZZ_pX NTLmipo= to_ZZ_pX (convertFacCF2NTLZZX (getMipo (alpha)));
786        ZZ_pE::init (NTLmipo);
787        ZZ_pEX NTLg= convertFacCF2NTLZZ_pEX (G, NTLmipo);
788        ZZ_pEX NTLf= convertFacCF2NTLZZ_pEX (F, NTLmipo);
789        rem (NTLf, NTLf, NTLg);
790        return b (convertNTLZZ_pEX2CF (NTLf, F.mvar(), alpha));
791#endif
792      }
793#ifdef HAVE_FLINT
794      CanonicalForm Q, R;
795      newtonDivrem (F, G, Q, R);
796      return R;
797#else
798      return mod (F,G);
799#endif
800    }
801  }
802
803  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
804  ASSERT (F.level() == G.level(), "expected polys of same level");
805#if (!defined(HAVE_FLINT) ||  __FLINT_RELEASE < 20400)
806  if (fac_NTL_char != getCharacteristic())
807  {
808    fac_NTL_char= getCharacteristic();
809    zz_p::init (getCharacteristic());
810  }
811#endif
812  Variable alpha;
813  CanonicalForm result;
814  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
815  {
816#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
817    nmod_poly_t FLINTmipo;
818    fq_nmod_ctx_t fq_con;
819
820    nmod_poly_init (FLINTmipo, getCharacteristic());
821    convertFacCF2nmod_poly_t (FLINTmipo, getMipo (alpha));
822
823    fq_nmod_ctx_init_modulus (fq_con, FLINTmipo, "Z");
824
825    fq_nmod_poly_t FLINTF, FLINTG;
826    convertFacCF2Fq_nmod_poly_t (FLINTF, F, fq_con);
827    convertFacCF2Fq_nmod_poly_t (FLINTG, G, fq_con);
828
829    fq_nmod_poly_rem (FLINTF, FLINTF, FLINTG, fq_con);
830
831    result= convertFq_nmod_poly_t2FacCF (FLINTF, F.mvar(), alpha, fq_con);
832
833    fq_nmod_poly_clear (FLINTF, fq_con);
834    fq_nmod_poly_clear (FLINTG, fq_con);
835    nmod_poly_clear (FLINTmipo);
836    fq_nmod_ctx_clear (fq_con);
837#else
838    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
839    zz_pE::init (NTLMipo);
840    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
841    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
842    rem (NTLF, NTLF, NTLG);
843    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
844#endif
845  }
846  else
847  {
848#ifdef HAVE_FLINT
849    nmod_poly_t FLINTF, FLINTG;
850    convertFacCF2nmod_poly_t (FLINTF, F);
851    convertFacCF2nmod_poly_t (FLINTG, G);
852    nmod_poly_divrem (FLINTG, FLINTF, FLINTF, FLINTG);
853    result= convertnmod_poly_t2FacCF (FLINTF, F.mvar());
854    nmod_poly_clear (FLINTF);
855    nmod_poly_clear (FLINTG);
856#else
857    zz_pX NTLF= convertFacCF2NTLzzpX (F);
858    zz_pX NTLG= convertFacCF2NTLzzpX (G);
859    rem (NTLF, NTLF, NTLG);
860    result= convertNTLzzpX2CF(NTLF, F.mvar());
861#endif
862  }
863  return result;
864}
865
866CanonicalForm
867divNTL (const CanonicalForm& F, const CanonicalForm& G, const modpk& b)
868{
869  if (CFFactory::gettype() == GaloisFieldDomain)
870    return div (F, G);
871  if (F.inCoeffDomain() && G.isUnivariate() && !G.inCoeffDomain())
872  {
873    return 0;
874  }
875  else if (F.inCoeffDomain() && G.inCoeffDomain())
876  {
877    if (b.getp() != 0)
878    {
879      if (!F.inBaseDomain() || !G.inBaseDomain())
880      {
881        Variable alpha;
882        hasFirstAlgVar (F, alpha);
883        hasFirstAlgVar (G, alpha);
884#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
885        fmpz_t FLINTp;
886        fmpz_mod_poly_t FLINTmipo;
887        fq_ctx_t fq_con;
888        fq_t FLINTF, FLINTG;
889
890        fmpz_init (FLINTp);
891        convertCF2Fmpz (FLINTp, b.getpk());
892
893        convertFacCF2Fmpz_mod_poly_t (FLINTmipo, getMipo (alpha), FLINTp);
894
895        fq_ctx_init_modulus (fq_con, FLINTmipo, "Z");
896
897        convertFacCF2Fq_t (FLINTF, F, fq_con);
898        convertFacCF2Fq_t (FLINTG, G, fq_con);
899
900        fq_inv (FLINTG, FLINTG, fq_con);
901        fq_mul (FLINTF, FLINTF, FLINTG, fq_con);
902
903        CanonicalForm result= convertFq_t2FacCF (FLINTF, alpha);
904
905        fmpz_clear (FLINTp);
906        fmpz_mod_poly_clear (FLINTmipo);
907        fq_clear (FLINTF, fq_con);
908        fq_clear (FLINTG, fq_con);
909        fq_ctx_clear (fq_con);
910        return b (result);
911#else
912        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
913        ZZ_pX NTLmipo= to_ZZ_pX (convertFacCF2NTLZZX (getMipo (alpha)));
914        ZZ_pE::init (NTLmipo);
915        ZZ_pX NTLg= convertFacCF2NTLZZpX (G);
916        ZZ_pX NTLf= convertFacCF2NTLZZpX (F);
917        ZZ_pE result;
918        div (result, to_ZZ_pE (NTLf), to_ZZ_pE (NTLg));
919        return b (convertNTLZZpX2CF (rep (result), alpha));
920#endif
921      }
922      return b(div (F,G));
923    }
924    return div (F, G);
925  }
926  else if (F.isUnivariate() && G.inCoeffDomain())
927  {
928    if (b.getp() != 0)
929    {
930      if (!G.inBaseDomain())
931      {
932        Variable alpha;
933        hasFirstAlgVar (G, alpha);
934#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
935        fmpz_t FLINTp;
936        fmpz_mod_poly_t FLINTmipo;
937        fq_ctx_t fq_con;
938        fq_poly_t FLINTF;
939        fq_t FLINTG;
940
941        fmpz_init (FLINTp);
942        convertCF2Fmpz (FLINTp, b.getpk());
943
944        convertFacCF2Fmpz_mod_poly_t (FLINTmipo, getMipo (alpha), FLINTp);
945
946        fq_ctx_init_modulus (fq_con, FLINTmipo, "Z");
947
948        convertFacCF2Fq_poly_t (FLINTF, F, fq_con);
949        convertFacCF2Fq_t (FLINTG, G, fq_con);
950
951        fq_inv (FLINTG, FLINTG, fq_con);
952        fq_poly_scalar_mul_fq (FLINTF, FLINTF, FLINTG, fq_con);
953
954        CanonicalForm result= convertFq_poly_t2FacCF (FLINTF, F.mvar(),
955                                                      alpha, fq_con);
956
957        fmpz_clear (FLINTp);
958        fmpz_mod_poly_clear (FLINTmipo);
959        fq_poly_clear (FLINTF, fq_con);
960        fq_clear (FLINTG, fq_con);
961        fq_ctx_clear (fq_con);
962        return b (result);
963#else
964        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
965        ZZ_pX NTLmipo= to_ZZ_pX (convertFacCF2NTLZZX (getMipo (alpha)));
966        ZZ_pE::init (NTLmipo);
967        ZZ_pX NTLg= convertFacCF2NTLZZpX (G);
968        ZZ_pEX NTLf= convertFacCF2NTLZZ_pEX (F, NTLmipo);
969        div (NTLf, NTLf, to_ZZ_pE (NTLg));
970        return b (convertNTLZZ_pEX2CF (NTLf, F.mvar(), alpha));
971#endif
972      }
973      return b(div (F,G));
974    }
975    return div (F, G);
976  }
977
978  if (getCharacteristic() == 0)
979  {
980
981    Variable alpha;
982    if (!hasFirstAlgVar (F, alpha) && !hasFirstAlgVar (G, alpha))
983    {
984#ifdef HAVE_FLINT
985      if (b.getp() != 0)
986      {
987        fmpz_t FLINTpk;
988        fmpz_init (FLINTpk);
989        convertCF2Fmpz (FLINTpk, b.getpk());
990        fmpz_mod_poly_t FLINTF, FLINTG;
991        convertFacCF2Fmpz_mod_poly_t (FLINTF, F, FLINTpk);
992        convertFacCF2Fmpz_mod_poly_t (FLINTG, G, FLINTpk);
993        fmpz_mod_poly_divrem (FLINTF, FLINTG, FLINTF, FLINTG);
994        CanonicalForm result= convertFmpz_mod_poly_t2FacCF (FLINTF,F.mvar(),b);
995        fmpz_mod_poly_clear (FLINTG);
996        fmpz_mod_poly_clear (FLINTF);
997        fmpz_clear (FLINTpk);
998        return result;
999      }
1000      return divFLINTQ (F,G);
1001#else
1002      if (b.getp() != 0)
1003      {
1004        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
1005        ZZX ZZf= convertFacCF2NTLZZX (F);
1006        ZZX ZZg= convertFacCF2NTLZZX (G);
1007        ZZ_pX NTLf= to_ZZ_pX (ZZf);
1008        ZZ_pX NTLg= to_ZZ_pX (ZZg);
1009        div (NTLf, NTLf, NTLg);
1010        return b (convertNTLZZX2CF (to_ZZX (NTLf), F.mvar()));
1011      }
1012      return div (F, G);
1013#endif
1014    }
1015    else
1016    {
1017      if (b.getp() != 0)
1018      {
1019#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
1020        fmpz_t FLINTp;
1021        fmpz_mod_poly_t FLINTmipo;
1022        fq_ctx_t fq_con;
1023        fq_poly_t FLINTF, FLINTG;
1024
1025        fmpz_init (FLINTp);
1026        convertCF2Fmpz (FLINTp, b.getpk());
1027
1028        convertFacCF2Fmpz_mod_poly_t (FLINTmipo, getMipo (alpha), FLINTp);
1029
1030        fq_ctx_init_modulus (fq_con, FLINTmipo, "Z");
1031
1032        convertFacCF2Fq_poly_t (FLINTF, F, fq_con);
1033        convertFacCF2Fq_poly_t (FLINTG, G, fq_con);
1034
1035        fq_poly_divrem (FLINTF, FLINTG, FLINTF, FLINTG, fq_con);
1036
1037        CanonicalForm result= convertFq_poly_t2FacCF (FLINTF, F.mvar(),
1038                                                      alpha, fq_con);
1039
1040        fmpz_clear (FLINTp);
1041        fmpz_mod_poly_clear (FLINTmipo);
1042        fq_ctx_clear (fq_con);
1043        fq_poly_clear (FLINTF, fq_con);
1044        fq_poly_clear (FLINTG, fq_con);
1045        return b (result);
1046#else
1047        ZZ_p::init (convertFacCF2NTLZZ (b.getpk()));
1048        ZZ_pX NTLmipo= to_ZZ_pX (convertFacCF2NTLZZX (getMipo (alpha)));
1049        ZZ_pE::init (NTLmipo);
1050        ZZ_pEX NTLg= convertFacCF2NTLZZ_pEX (G, NTLmipo);
1051        ZZ_pEX NTLf= convertFacCF2NTLZZ_pEX (F, NTLmipo);
1052        div (NTLf, NTLf, NTLg);
1053        return b (convertNTLZZ_pEX2CF (NTLf, F.mvar(), alpha));
1054#endif
1055      }
1056#ifdef HAVE_FLINT
1057      CanonicalForm Q;
1058      newtonDiv (F, G, Q);
1059      return Q;
1060#else
1061      return div (F,G);
1062#endif
1063    }
1064  }
1065
1066  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
1067  ASSERT (F.level() == G.level(), "expected polys of same level");
1068#if (!defined(HAVE_FLINT) ||  __FLINT_RELEASE < 20400)
1069  if (fac_NTL_char != getCharacteristic())
1070  {
1071    fac_NTL_char= getCharacteristic();
1072    zz_p::init (getCharacteristic());
1073  }
1074#endif
1075  Variable alpha;
1076  CanonicalForm result;
1077  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
1078  {
1079#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
1080    nmod_poly_t FLINTmipo;
1081    fq_nmod_ctx_t fq_con;
1082
1083    nmod_poly_init (FLINTmipo, getCharacteristic());
1084    convertFacCF2nmod_poly_t (FLINTmipo, getMipo (alpha));
1085
1086    fq_nmod_ctx_init_modulus (fq_con, FLINTmipo, "Z");
1087
1088    fq_nmod_poly_t FLINTF, FLINTG;
1089    convertFacCF2Fq_nmod_poly_t (FLINTF, F, fq_con);
1090    convertFacCF2Fq_nmod_poly_t (FLINTG, G, fq_con);
1091
1092    fq_nmod_poly_divrem (FLINTF, FLINTG, FLINTF, FLINTG, fq_con);
1093
1094    result= convertFq_nmod_poly_t2FacCF (FLINTF, F.mvar(), alpha, fq_con);
1095
1096    fq_nmod_poly_clear (FLINTF, fq_con);
1097    fq_nmod_poly_clear (FLINTG, fq_con);
1098    nmod_poly_clear (FLINTmipo);
1099    fq_nmod_ctx_clear (fq_con);
1100#else
1101    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
1102    zz_pE::init (NTLMipo);
1103    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
1104    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
1105    div (NTLF, NTLF, NTLG);
1106    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
1107#endif
1108  }
1109  else
1110  {
1111#ifdef HAVE_FLINT
1112    nmod_poly_t FLINTF, FLINTG;
1113    convertFacCF2nmod_poly_t (FLINTF, F);
1114    convertFacCF2nmod_poly_t (FLINTG, G);
1115    nmod_poly_div (FLINTF, FLINTF, FLINTG);
1116    result= convertnmod_poly_t2FacCF (FLINTF, F.mvar());
1117    nmod_poly_clear (FLINTF);
1118    nmod_poly_clear (FLINTG);
1119#else
1120    zz_pX NTLF= convertFacCF2NTLzzpX (F);
1121    zz_pX NTLG= convertFacCF2NTLzzpX (G);
1122    div (NTLF, NTLF, NTLG);
1123    result= convertNTLzzpX2CF(NTLF, F.mvar());
1124#endif
1125  }
1126  return result;
1127}
1128
1129// end univariate polys
1130//*************************
1131// bivariate polys
1132
1133#ifdef HAVE_FLINT
1134void kronSubFp (nmod_poly_t result, const CanonicalForm& A, int d)
1135{
1136  int degAy= degree (A);
1137  nmod_poly_init2 (result, getCharacteristic(), d*(degAy + 1));
1138  result->length= d*(degAy + 1);
1139  flint_mpn_zero (result->coeffs, d*(degAy+1));
1140
1141  nmod_poly_t buf;
1142
1143  int k;
1144  for (CFIterator i= A; i.hasTerms(); i++)
1145  {
1146    convertFacCF2nmod_poly_t (buf, i.coeff());
1147    k= i.exp()*d;
1148    flint_mpn_copyi (result->coeffs+k, buf->coeffs, nmod_poly_length(buf));
1149
1150    nmod_poly_clear (buf);
1151  }
1152  _nmod_poly_normalise (result);
1153}
1154
1155#if ( __FLINT_RELEASE >= 20400)
1156void
1157kronSubFq (fq_nmod_poly_t result, const CanonicalForm& A, int d,
1158           const fq_nmod_ctx_t fq_con)
1159{
1160  int degAy= degree (A);
1161  fq_nmod_poly_init2 (result, d*(degAy + 1), fq_con);
1162  _fq_nmod_poly_set_length (result, d*(degAy + 1), fq_con);
1163  _fq_nmod_vec_zero (result->coeffs, d*(degAy + 1), fq_con);
1164
1165  fq_nmod_poly_t buf1;
1166
1167  nmod_poly_t buf2;
1168
1169  int k;
1170
1171  for (CFIterator i= A; i.hasTerms(); i++)
1172  {
1173    if (i.coeff().inCoeffDomain())
1174    {
1175      convertFacCF2nmod_poly_t (buf2, i.coeff());
1176      fq_nmod_poly_init2 (buf1, 1, fq_con);
1177      fq_nmod_poly_set_coeff (buf1, 0, buf2, fq_con);
1178      nmod_poly_clear (buf2);
1179    }
1180    else
1181      convertFacCF2Fq_nmod_poly_t (buf1, i.coeff(), fq_con);
1182
1183    k= i.exp()*d;
1184    _fq_nmod_vec_set (result->coeffs+k, buf1->coeffs,
1185                      fq_nmod_poly_length (buf1, fq_con), fq_con);
1186
1187    fq_nmod_poly_clear (buf1, fq_con);
1188  }
1189
1190  _fq_nmod_poly_normalise (result, fq_con);
1191}
1192#endif
1193
1194/*void kronSubQa (fmpq_poly_t result, const CanonicalForm& A, int d1, int d2)
1195{
1196  int degAy= degree (A);
1197  fmpq_poly_init2 (result, d1*(degAy + 1));
1198
1199  fmpq_poly_t buf;
1200  fmpq_t coeff;
1201
1202  int k, l, bufRepLength;
1203  CFIterator j;
1204  for (CFIterator i= A; i.hasTerms(); i++)
1205  {
1206    if (i.coeff().inCoeffDomain())
1207    {
1208      k= d1*i.exp();
1209      convertFacCF2Fmpq_poly_t (buf, i.coeff());
1210      bufRepLength= (int) fmpq_poly_length(buf);
1211      for (l= 0; l < bufRepLength; l++)
1212      {
1213        fmpq_poly_get_coeff_fmpq (coeff, buf, l);
1214        fmpq_poly_set_coeff_fmpq (result, l + k, coeff);
1215      }
1216      fmpq_poly_clear (buf);
1217    }
1218    else
1219    {
1220      for (j= i.coeff(); j.hasTerms(); j++)
1221      {
1222        k= d1*i.exp();
1223        k += d2*j.exp();
1224        convertFacCF2Fmpq_poly_t (buf, j.coeff());
1225        bufRepLength= (int) fmpq_poly_length(buf);
1226        for (l= 0; l < bufRepLength; l++)
1227        {
1228          fmpq_poly_get_coeff_fmpq (coeff, buf, l);
1229          fmpq_poly_set_coeff_fmpq (result, k + l, coeff);
1230        }
1231        fmpq_poly_clear (buf);
1232      }
1233    }
1234  }
1235  fmpq_clear (coeff);
1236  _fmpq_poly_normalise (result);
1237}*/
1238
1239void kronSubQa (fmpz_poly_t result, const CanonicalForm& A, int d1, int d2)
1240{
1241  int degAy= degree (A);
1242  fmpz_poly_init2 (result, d1*(degAy + 1));
1243  _fmpz_poly_set_length (result, d1*(degAy + 1));
1244
1245  fmpz_poly_t buf;
1246
1247  int k;
1248  CFIterator j;
1249  for (CFIterator i= A; i.hasTerms(); i++)
1250  {
1251    if (i.coeff().inCoeffDomain())
1252    {
1253      k= d1*i.exp();
1254      convertFacCF2Fmpz_poly_t (buf, i.coeff());
1255      _fmpz_vec_set (result->coeffs + k, buf->coeffs, buf->length);
1256      fmpz_poly_clear (buf);
1257    }
1258    else
1259    {
1260      for (j= i.coeff(); j.hasTerms(); j++)
1261      {
1262        k= d1*i.exp();
1263        k += d2*j.exp();
1264        convertFacCF2Fmpz_poly_t (buf, j.coeff());
1265        _fmpz_vec_set (result->coeffs + k, buf->coeffs, buf->length);
1266        fmpz_poly_clear (buf);
1267      }
1268    }
1269  }
1270  _fmpz_poly_normalise (result);
1271}
1272
1273void
1274kronSubReciproFp (nmod_poly_t subA1, nmod_poly_t subA2, const CanonicalForm& A,
1275                  int d)
1276{
1277  int degAy= degree (A);
1278  mp_limb_t ninv= n_preinvert_limb (getCharacteristic());
1279  nmod_poly_init2_preinv (subA1, getCharacteristic(), ninv, d*(degAy + 2));
1280  nmod_poly_init2_preinv (subA2, getCharacteristic(), ninv, d*(degAy + 2));
1281
1282  nmod_poly_t buf;
1283
1284  int k, kk, j, bufRepLength;
1285  for (CFIterator i= A; i.hasTerms(); i++)
1286  {
1287    convertFacCF2nmod_poly_t (buf, i.coeff());
1288
1289    k= i.exp()*d;
1290    kk= (degAy - i.exp())*d;
1291    bufRepLength= (int) nmod_poly_length (buf);
1292    for (j= 0; j < bufRepLength; j++)
1293    {
1294      nmod_poly_set_coeff_ui (subA1, j + k,
1295                              n_addmod (nmod_poly_get_coeff_ui (subA1, j+k),
1296                                        nmod_poly_get_coeff_ui (buf, j),
1297                                        getCharacteristic()
1298                                       )
1299                             );
1300      nmod_poly_set_coeff_ui (subA2, j + kk,
1301                              n_addmod (nmod_poly_get_coeff_ui (subA2, j + kk),
1302                                        nmod_poly_get_coeff_ui (buf, j),
1303                                        getCharacteristic()
1304                                       )
1305                             );
1306    }
1307    nmod_poly_clear (buf);
1308  }
1309  _nmod_poly_normalise (subA1);
1310  _nmod_poly_normalise (subA2);
1311}
1312
1313#if ( __FLINT_RELEASE >= 20400)
1314void
1315kronSubReciproFq (fq_nmod_poly_t subA1, fq_nmod_poly_t subA2,
1316                  const CanonicalForm& A, int d, const fq_nmod_ctx_t fq_con)
1317{
1318  int degAy= degree (A);
1319  fq_nmod_poly_init2 (subA1, d*(degAy + 2), fq_con);
1320  fq_nmod_poly_init2 (subA2, d*(degAy + 2), fq_con);
1321
1322  _fq_nmod_poly_set_length (subA1, d*(degAy + 2), fq_con);
1323  _fq_nmod_vec_zero (subA1->coeffs, d*(degAy + 2), fq_con);
1324
1325  _fq_nmod_poly_set_length (subA2, d*(degAy + 2), fq_con);
1326  _fq_nmod_vec_zero (subA2->coeffs, d*(degAy + 2), fq_con);
1327
1328  fq_nmod_poly_t buf1;
1329
1330  nmod_poly_t buf2;
1331
1332  int k, kk;
1333  for (CFIterator i= A; i.hasTerms(); i++)
1334  {
1335    if (i.coeff().inCoeffDomain())
1336    {
1337      convertFacCF2nmod_poly_t (buf2, i.coeff());
1338      fq_nmod_poly_init2 (buf1, 1, fq_con);
1339      fq_nmod_poly_set_coeff (buf1, 0, buf2, fq_con);
1340      nmod_poly_clear (buf2);
1341    }
1342    else
1343      convertFacCF2Fq_nmod_poly_t (buf1, i.coeff(), fq_con);
1344
1345    k= i.exp()*d;
1346    kk= (degAy - i.exp())*d;
1347    _fq_nmod_vec_add (subA1->coeffs+k, subA1->coeffs+k, buf1->coeffs,
1348                      fq_nmod_poly_length(buf1, fq_con), fq_con);
1349    _fq_nmod_vec_add (subA2->coeffs+kk, subA2->coeffs+kk, buf1->coeffs,
1350                      fq_nmod_poly_length(buf1, fq_con), fq_con);
1351
1352    fq_nmod_poly_clear (buf1, fq_con);
1353  }
1354  _fq_nmod_poly_normalise (subA1, fq_con);
1355  _fq_nmod_poly_normalise (subA2, fq_con);
1356}
1357#endif
1358
1359void
1360kronSubReciproQ (fmpz_poly_t subA1, fmpz_poly_t subA2, const CanonicalForm& A,
1361                 int d)
1362{
1363  int degAy= degree (A);
1364  fmpz_poly_init2 (subA1, d*(degAy + 2));
1365  fmpz_poly_init2 (subA2, d*(degAy + 2));
1366
1367  fmpz_poly_t buf;
1368
1369  int k, kk;
1370  for (CFIterator i= A; i.hasTerms(); i++)
1371  {
1372    convertFacCF2Fmpz_poly_t (buf, i.coeff());
1373
1374    k= i.exp()*d;
1375    kk= (degAy - i.exp())*d;
1376    _fmpz_vec_add (subA1->coeffs+k, subA1->coeffs + k, buf->coeffs, buf->length);
1377    _fmpz_vec_add (subA2->coeffs+kk, subA2->coeffs + kk, buf->coeffs, buf->length);
1378    fmpz_poly_clear (buf);
1379  }
1380
1381  _fmpz_poly_normalise (subA1);
1382  _fmpz_poly_normalise (subA2);
1383}
1384
1385CanonicalForm reverseSubstQ (const fmpz_poly_t F, int d)
1386{
1387  Variable y= Variable (2);
1388  Variable x= Variable (1);
1389
1390  fmpz_poly_t buf;
1391  CanonicalForm result= 0;
1392  int i= 0;
1393  int degf= fmpz_poly_degree(F);
1394  int k= 0;
1395  int degfSubK, repLength;
1396  while (degf >= k)
1397  {
1398    degfSubK= degf - k;
1399    if (degfSubK >= d)
1400      repLength= d;
1401    else
1402      repLength= degfSubK + 1;
1403
1404    fmpz_poly_init2 (buf, repLength);
1405    _fmpz_poly_set_length (buf, repLength);
1406    _fmpz_vec_set (buf->coeffs, F->coeffs+k, repLength);
1407    _fmpz_poly_normalise (buf);
1408
1409    result += convertFmpz_poly_t2FacCF (buf, x)*power (y, i);
1410    i++;
1411    k= d*i;
1412    fmpz_poly_clear (buf);
1413  }
1414
1415  return result;
1416}
1417
1418/*CanonicalForm
1419reverseSubstQa (const fmpq_poly_t F, int d1, int d2, const Variable& alpha,
1420                const fmpq_poly_t mipo)
1421{
1422  Variable y= Variable (2);
1423  Variable x= Variable (1);
1424
1425  fmpq_poly_t f;
1426  fmpq_poly_init (f);
1427  fmpq_poly_set (f, F);
1428
1429  fmpq_poly_t buf;
1430  CanonicalForm result= 0, result2;
1431  int i= 0;
1432  int degf= fmpq_poly_degree(f);
1433  int k= 0;
1434  int degfSubK;
1435  int repLength;
1436  fmpq_t coeff;
1437  while (degf >= k)
1438  {
1439    degfSubK= degf - k;
1440    if (degfSubK >= d1)
1441      repLength= d1;
1442    else
1443      repLength= degfSubK + 1;
1444
1445    fmpq_init (coeff);
1446    int j= 0;
1447    int l;
1448    result2= 0;
1449    while (j*d2 < repLength)
1450    {
1451      fmpq_poly_init2 (buf, d2);
1452      for (l= 0; l < d2; l++)
1453      {
1454        fmpq_poly_get_coeff_fmpq (coeff, f, k + j*d2 + l);
1455        fmpq_poly_set_coeff_fmpq (buf, l, coeff);
1456      }
1457      _fmpq_poly_normalise (buf);
1458      fmpq_poly_rem (buf, buf, mipo);
1459      result2 += convertFmpq_poly_t2FacCF (buf, alpha)*power (x, j);
1460      j++;
1461      fmpq_poly_clear (buf);
1462    }
1463    if (repLength - j*d2 != 0 && j*d2 - repLength < d2)
1464    {
1465      j--;
1466      repLength -= j*d2;
1467      fmpq_poly_init2 (buf, repLength);
1468      j++;
1469      for (l= 0; l < repLength; l++)
1470      {
1471        fmpq_poly_get_coeff_fmpq (coeff, f, k + j*d2 + l);
1472        fmpq_poly_set_coeff_fmpq (buf, l, coeff);
1473      }
1474      _fmpq_poly_normalise (buf);
1475      fmpq_poly_rem (buf, buf, mipo);
1476      result2 += convertFmpq_poly_t2FacCF (buf, alpha)*power (x, j);
1477      fmpq_poly_clear (buf);
1478    }
1479    fmpq_clear (coeff);
1480
1481    result += result2*power (y, i);
1482    i++;
1483    k= d1*i;
1484  }
1485
1486  fmpq_poly_clear (f);
1487  return result;
1488}*/
1489
1490CanonicalForm
1491reverseSubstQa (const fmpz_poly_t F, int d1, int d2, const Variable& alpha,
1492                const fmpq_poly_t mipo)
1493{
1494  Variable y= Variable (2);
1495  Variable x= Variable (1);
1496
1497  fmpq_poly_t buf;
1498  CanonicalForm result= 0, result2;
1499  int i= 0;
1500  int degf= fmpz_poly_degree(F);
1501  int k= 0;
1502  int degfSubK;
1503  int repLength;
1504  while (degf >= k)
1505  {
1506    degfSubK= degf - k;
1507    if (degfSubK >= d1)
1508      repLength= d1;
1509    else
1510      repLength= degfSubK + 1;
1511
1512    int j= 0;
1513    result2= 0;
1514    while (j*d2 < repLength)
1515    {
1516      fmpq_poly_init2 (buf, d2);
1517      _fmpq_poly_set_length (buf, d2);
1518      _fmpz_vec_set (buf->coeffs, F->coeffs + k + j*d2, d2);
1519      _fmpq_poly_normalise (buf);
1520      fmpq_poly_rem (buf, buf, mipo);
1521      result2 += convertFmpq_poly_t2FacCF (buf, alpha)*power (x, j);
1522      j++;
1523      fmpq_poly_clear (buf);
1524    }
1525    if (repLength - j*d2 != 0 && j*d2 - repLength < d2)
1526    {
1527      j--;
1528      repLength -= j*d2;
1529      fmpq_poly_init2 (buf, repLength);
1530      _fmpq_poly_set_length (buf, repLength);
1531      j++;
1532      _fmpz_vec_set (buf->coeffs, F->coeffs + k + j*d2, repLength);
1533      _fmpq_poly_normalise (buf);
1534      fmpq_poly_rem (buf, buf, mipo);
1535      result2 += convertFmpq_poly_t2FacCF (buf, alpha)*power (x, j);
1536      fmpq_poly_clear (buf);
1537    }
1538
1539    result += result2*power (y, i);
1540    i++;
1541    k= d1*i;
1542  }
1543
1544  return result;
1545}
1546
1547CanonicalForm
1548reverseSubstReciproFp (const nmod_poly_t F, const nmod_poly_t G, int d, int k)
1549{
1550  Variable y= Variable (2);
1551  Variable x= Variable (1);
1552
1553  nmod_poly_t f, g;
1554  mp_limb_t ninv= n_preinvert_limb (getCharacteristic());
1555  nmod_poly_init_preinv (f, getCharacteristic(), ninv);
1556  nmod_poly_init_preinv (g, getCharacteristic(), ninv);
1557  nmod_poly_set (f, F);
1558  nmod_poly_set (g, G);
1559  int degf= nmod_poly_degree(f);
1560  int degg= nmod_poly_degree(g);
1561
1562
1563  nmod_poly_t buf1,buf2, buf3;
1564
1565  if (nmod_poly_length (f) < (long) d*(k+1)) //zero padding
1566    nmod_poly_fit_length (f,(long)d*(k+1));
1567
1568  CanonicalForm result= 0;
1569  int i= 0;
1570  int lf= 0;
1571  int lg= d*k;
1572  int degfSubLf= degf;
1573  int deggSubLg= degg-lg;
1574  int repLengthBuf2, repLengthBuf1, ind, tmp;
1575  while (degf >= lf || lg >= 0)
1576  {
1577    if (degfSubLf >= d)
1578      repLengthBuf1= d;
1579    else if (degfSubLf < 0)
1580      repLengthBuf1= 0;
1581    else
1582      repLengthBuf1= degfSubLf + 1;
1583    nmod_poly_init2_preinv (buf1, getCharacteristic(), ninv, repLengthBuf1);
1584
1585    for (ind= 0; ind < repLengthBuf1; ind++)
1586      nmod_poly_set_coeff_ui (buf1, ind, nmod_poly_get_coeff_ui (f, ind+lf));
1587    _nmod_poly_normalise (buf1);
1588
1589    repLengthBuf1= nmod_poly_length (buf1);
1590
1591    if (deggSubLg >= d - 1)
1592      repLengthBuf2= d - 1;
1593    else if (deggSubLg < 0)
1594      repLengthBuf2= 0;
1595    else
1596      repLengthBuf2= deggSubLg + 1;
1597
1598    nmod_poly_init2_preinv (buf2, getCharacteristic(), ninv, repLengthBuf2);
1599    for (ind= 0; ind < repLengthBuf2; ind++)
1600      nmod_poly_set_coeff_ui (buf2, ind, nmod_poly_get_coeff_ui (g, ind + lg));
1601
1602    _nmod_poly_normalise (buf2);
1603    repLengthBuf2= nmod_poly_length (buf2);
1604
1605    nmod_poly_init2_preinv (buf3, getCharacteristic(), ninv, repLengthBuf2 + d);
1606    for (ind= 0; ind < repLengthBuf1; ind++)
1607      nmod_poly_set_coeff_ui (buf3, ind, nmod_poly_get_coeff_ui (buf1, ind));
1608    for (ind= repLengthBuf1; ind < d; ind++)
1609      nmod_poly_set_coeff_ui (buf3, ind, 0);
1610    for (ind= 0; ind < repLengthBuf2; ind++)
1611      nmod_poly_set_coeff_ui (buf3, ind+d, nmod_poly_get_coeff_ui (buf2, ind));
1612    _nmod_poly_normalise (buf3);
1613
1614    result += convertnmod_poly_t2FacCF (buf3, x)*power (y, i);
1615    i++;
1616
1617
1618    lf= i*d;
1619    degfSubLf= degf - lf;
1620
1621    lg= d*(k-i);
1622    deggSubLg= degg - lg;
1623
1624    if (lg >= 0 && deggSubLg > 0)
1625    {
1626      if (repLengthBuf2 > degfSubLf + 1)
1627        degfSubLf= repLengthBuf2 - 1;
1628      tmp= tmin (repLengthBuf1, deggSubLg + 1);
1629      for (ind= 0; ind < tmp; ind++)
1630        nmod_poly_set_coeff_ui (g, ind + lg,
1631                                n_submod (nmod_poly_get_coeff_ui (g, ind + lg),
1632                                          nmod_poly_get_coeff_ui (buf1, ind),
1633                                          getCharacteristic()
1634                                         )
1635                               );
1636    }
1637    if (lg < 0)
1638    {
1639      nmod_poly_clear (buf1);
1640      nmod_poly_clear (buf2);
1641      nmod_poly_clear (buf3);
1642      break;
1643    }
1644    if (degfSubLf >= 0)
1645    {
1646      for (ind= 0; ind < repLengthBuf2; ind++)
1647        nmod_poly_set_coeff_ui (f, ind + lf,
1648                                n_submod (nmod_poly_get_coeff_ui (f, ind + lf),
1649                                          nmod_poly_get_coeff_ui (buf2, ind),
1650                                          getCharacteristic()
1651                                         )
1652                               );
1653    }
1654    nmod_poly_clear (buf1);
1655    nmod_poly_clear (buf2);
1656    nmod_poly_clear (buf3);
1657  }
1658
1659  nmod_poly_clear (f);
1660  nmod_poly_clear (g);
1661
1662  return result;
1663}
1664
1665#if ( __FLINT_RELEASE >= 20400)
1666CanonicalForm
1667reverseSubstReciproFq (const fq_nmod_poly_t F, const fq_nmod_poly_t G, int d,
1668                       int k, const Variable& alpha, const fq_nmod_ctx_t fq_con)
1669{
1670  Variable y= Variable (2);
1671  Variable x= Variable (1);
1672
1673  fq_nmod_poly_t f, g;
1674  int degf= fq_nmod_poly_degree(F, fq_con);
1675  int degg= fq_nmod_poly_degree(G, fq_con);
1676
1677  fq_nmod_poly_t buf1,buf2, buf3;
1678
1679  fq_nmod_poly_init (f, fq_con);
1680  fq_nmod_poly_init (g, fq_con);
1681  fq_nmod_poly_set (f, F, fq_con);
1682  fq_nmod_poly_set (g, G, fq_con);
1683  if (fq_nmod_poly_length (f, fq_con) < (long) d*(k + 1)) //zero padding
1684    fq_nmod_poly_fit_length (f, (long) d*(k + 1), fq_con);
1685
1686  CanonicalForm result= 0;
1687  int i= 0;
1688  int lf= 0;
1689  int lg= d*k;
1690  int degfSubLf= degf;
1691  int deggSubLg= degg-lg;
1692  int repLengthBuf2, repLengthBuf1, tmp;
1693  while (degf >= lf || lg >= 0)
1694  {
1695    if (degfSubLf >= d)
1696      repLengthBuf1= d;
1697    else if (degfSubLf < 0)
1698      repLengthBuf1= 0;
1699    else
1700      repLengthBuf1= degfSubLf + 1;
1701    fq_nmod_poly_init2 (buf1, repLengthBuf1, fq_con);
1702    _fq_nmod_poly_set_length (buf1, repLengthBuf1, fq_con);
1703
1704    _fq_nmod_vec_set (buf1->coeffs, f->coeffs + lf, repLengthBuf1, fq_con);
1705    _fq_nmod_poly_normalise (buf1, fq_con);
1706
1707    repLengthBuf1= fq_nmod_poly_length (buf1, fq_con);
1708
1709    if (deggSubLg >= d - 1)
1710      repLengthBuf2= d - 1;
1711    else if (deggSubLg < 0)
1712      repLengthBuf2= 0;
1713    else
1714      repLengthBuf2= deggSubLg + 1;
1715
1716    fq_nmod_poly_init2 (buf2, repLengthBuf2, fq_con);
1717    _fq_nmod_poly_set_length (buf2, repLengthBuf2, fq_con);
1718    _fq_nmod_vec_set (buf2->coeffs, g->coeffs + lg, repLengthBuf2, fq_con);
1719
1720    _fq_nmod_poly_normalise (buf2, fq_con);
1721    repLengthBuf2= fq_nmod_poly_length (buf2, fq_con);
1722
1723    fq_nmod_poly_init2 (buf3, repLengthBuf2 + d, fq_con);
1724    _fq_nmod_poly_set_length (buf3, repLengthBuf2 + d, fq_con);
1725    _fq_nmod_vec_set (buf3->coeffs, buf1->coeffs, repLengthBuf1, fq_con);
1726    _fq_nmod_vec_set (buf3->coeffs + d, buf2->coeffs, repLengthBuf2, fq_con);
1727
1728    _fq_nmod_poly_normalise (buf3, fq_con);
1729
1730    result += convertFq_nmod_poly_t2FacCF (buf3, x, alpha, fq_con)*power (y, i);
1731    i++;
1732
1733
1734    lf= i*d;
1735    degfSubLf= degf - lf;
1736
1737    lg= d*(k - i);
1738    deggSubLg= degg - lg;
1739
1740    if (lg >= 0 && deggSubLg > 0)
1741    {
1742      if (repLengthBuf2 > degfSubLf + 1)
1743        degfSubLf= repLengthBuf2 - 1;
1744      tmp= tmin (repLengthBuf1, deggSubLg + 1);
1745      _fq_nmod_vec_sub (g->coeffs + lg, g->coeffs + lg, buf1-> coeffs,
1746                        tmp, fq_con);
1747    }
1748    if (lg < 0)
1749    {
1750      fq_nmod_poly_clear (buf1, fq_con);
1751      fq_nmod_poly_clear (buf2, fq_con);
1752      fq_nmod_poly_clear (buf3, fq_con);
1753      break;
1754    }
1755    if (degfSubLf >= 0)
1756      _fq_nmod_vec_sub (f->coeffs + lf, f->coeffs + lf, buf2->coeffs,
1757                        repLengthBuf2, fq_con);
1758    fq_nmod_poly_clear (buf1, fq_con);
1759    fq_nmod_poly_clear (buf2, fq_con);
1760    fq_nmod_poly_clear (buf3, fq_con);
1761  }
1762
1763  fq_nmod_poly_clear (f, fq_con);
1764  fq_nmod_poly_clear (g, fq_con);
1765
1766  return result;
1767}
1768#endif
1769
1770CanonicalForm
1771reverseSubstReciproQ (const fmpz_poly_t F, const fmpz_poly_t G, int d, int k)
1772{
1773  Variable y= Variable (2);
1774  Variable x= Variable (1);
1775
1776  fmpz_poly_t f, g;
1777  fmpz_poly_init (f);
1778  fmpz_poly_init (g);
1779  fmpz_poly_set (f, F);
1780  fmpz_poly_set (g, G);
1781  int degf= fmpz_poly_degree(f);
1782  int degg= fmpz_poly_degree(g);
1783
1784  fmpz_poly_t buf1,buf2, buf3;
1785
1786  if (fmpz_poly_length (f) < (long) d*(k+1)) //zero padding
1787    fmpz_poly_fit_length (f,(long)d*(k+1));
1788
1789  CanonicalForm result= 0;
1790  int i= 0;
1791  int lf= 0;
1792  int lg= d*k;
1793  int degfSubLf= degf;
1794  int deggSubLg= degg-lg;
1795  int repLengthBuf2, repLengthBuf1, ind, tmp;
1796  fmpz_t tmp1, tmp2;
1797  while (degf >= lf || lg >= 0)
1798  {
1799    if (degfSubLf >= d)
1800      repLengthBuf1= d;
1801    else if (degfSubLf < 0)
1802      repLengthBuf1= 0;
1803    else
1804      repLengthBuf1= degfSubLf + 1;
1805
1806    fmpz_poly_init2 (buf1, repLengthBuf1);
1807
1808    for (ind= 0; ind < repLengthBuf1; ind++)
1809    {
1810      fmpz_poly_get_coeff_fmpz (tmp1, f, ind + lf);
1811      fmpz_poly_set_coeff_fmpz (buf1, ind, tmp1);
1812    }
1813    _fmpz_poly_normalise (buf1);
1814
1815    repLengthBuf1= fmpz_poly_length (buf1);
1816
1817    if (deggSubLg >= d - 1)
1818      repLengthBuf2= d - 1;
1819    else if (deggSubLg < 0)
1820      repLengthBuf2= 0;
1821    else
1822      repLengthBuf2= deggSubLg + 1;
1823
1824    fmpz_poly_init2 (buf2, repLengthBuf2);
1825
1826    for (ind= 0; ind < repLengthBuf2; ind++)
1827    {
1828      fmpz_poly_get_coeff_fmpz (tmp1, g, ind + lg);
1829      fmpz_poly_set_coeff_fmpz (buf2, ind, tmp1);
1830    }
1831
1832    _fmpz_poly_normalise (buf2);
1833    repLengthBuf2= fmpz_poly_length (buf2);
1834
1835    fmpz_poly_init2 (buf3, repLengthBuf2 + d);
1836    for (ind= 0; ind < repLengthBuf1; ind++)
1837    {
1838      fmpz_poly_get_coeff_fmpz (tmp1, buf1, ind);
1839      fmpz_poly_set_coeff_fmpz (buf3, ind, tmp1);
1840    }
1841    for (ind= repLengthBuf1; ind < d; ind++)
1842      fmpz_poly_set_coeff_ui (buf3, ind, 0);
1843    for (ind= 0; ind < repLengthBuf2; ind++)
1844    {
1845      fmpz_poly_get_coeff_fmpz (tmp1, buf2, ind);
1846      fmpz_poly_set_coeff_fmpz (buf3, ind + d, tmp1);
1847    }
1848    _fmpz_poly_normalise (buf3);
1849
1850    result += convertFmpz_poly_t2FacCF (buf3, x)*power (y, i);
1851    i++;
1852
1853
1854    lf= i*d;
1855    degfSubLf= degf - lf;
1856
1857    lg= d*(k-i);
1858    deggSubLg= degg - lg;
1859
1860    if (lg >= 0 && deggSubLg > 0)
1861    {
1862      if (repLengthBuf2 > degfSubLf + 1)
1863        degfSubLf= repLengthBuf2 - 1;
1864      tmp= tmin (repLengthBuf1, deggSubLg + 1);
1865      for (ind= 0; ind < tmp; ind++)
1866      {
1867        fmpz_poly_get_coeff_fmpz (tmp1, g, ind + lg);
1868        fmpz_poly_get_coeff_fmpz (tmp2, buf1, ind);
1869        fmpz_sub (tmp1, tmp1, tmp2);
1870        fmpz_poly_set_coeff_fmpz (g, ind + lg, tmp1);
1871      }
1872    }
1873    if (lg < 0)
1874    {
1875      fmpz_poly_clear (buf1);
1876      fmpz_poly_clear (buf2);
1877      fmpz_poly_clear (buf3);
1878      break;
1879    }
1880    if (degfSubLf >= 0)
1881    {
1882      for (ind= 0; ind < repLengthBuf2; ind++)
1883      {
1884        fmpz_poly_get_coeff_fmpz (tmp1, f, ind + lf);
1885        fmpz_poly_get_coeff_fmpz (tmp2, buf2, ind);
1886        fmpz_sub (tmp1, tmp1, tmp2);
1887        fmpz_poly_set_coeff_fmpz (f, ind + lf, tmp1);
1888      }
1889    }
1890    fmpz_poly_clear (buf1);
1891    fmpz_poly_clear (buf2);
1892    fmpz_poly_clear (buf3);
1893  }
1894
1895  fmpz_poly_clear (f);
1896  fmpz_poly_clear (g);
1897  fmpz_clear (tmp1);
1898  fmpz_clear (tmp2);
1899
1900  return result;
1901}
1902
1903#if ( __FLINT_RELEASE >= 20400)
1904CanonicalForm
1905reverseSubstFq (const fq_nmod_poly_t F, int d, const Variable& alpha,
1906                const fq_nmod_ctx_t fq_con)
1907{
1908  Variable y= Variable (2);
1909  Variable x= Variable (1);
1910
1911  fq_nmod_poly_t buf;
1912  CanonicalForm result= 0;
1913  int i= 0;
1914  int degf= fq_nmod_poly_degree(F, fq_con);
1915  int k= 0;
1916  int degfSubK, repLength;
1917  while (degf >= k)
1918  {
1919    degfSubK= degf - k;
1920    if (degfSubK >= d)
1921      repLength= d;
1922    else
1923      repLength= degfSubK + 1;
1924
1925    fq_nmod_poly_init2 (buf, repLength, fq_con);
1926    _fq_nmod_poly_set_length (buf, repLength, fq_con);
1927    _fq_nmod_vec_set (buf->coeffs, F->coeffs+k, repLength, fq_con);
1928    _fq_nmod_poly_normalise (buf, fq_con);
1929
1930    result += convertFq_nmod_poly_t2FacCF (buf, x, alpha, fq_con)*power (y, i);
1931    i++;
1932    k= d*i;
1933    fq_nmod_poly_clear (buf, fq_con);
1934  }
1935
1936  return result;
1937}
1938#endif
1939
1940CanonicalForm reverseSubstFp (const nmod_poly_t F, int d)
1941{
1942  Variable y= Variable (2);
1943  Variable x= Variable (1);
1944
1945  mp_limb_t ninv= n_preinvert_limb (getCharacteristic());
1946
1947  nmod_poly_t buf;
1948  CanonicalForm result= 0;
1949  int i= 0;
1950  int degf= nmod_poly_degree(F);
1951  int k= 0;
1952  int degfSubK, repLength, j;
1953  while (degf >= k)
1954  {
1955    degfSubK= degf - k;
1956    if (degfSubK >= d)
1957      repLength= d;
1958    else
1959      repLength= degfSubK + 1;
1960
1961    nmod_poly_init2_preinv (buf, getCharacteristic(), ninv, repLength);
1962    for (j= 0; j < repLength; j++)
1963      nmod_poly_set_coeff_ui (buf, j, nmod_poly_get_coeff_ui (F, j + k));
1964    _nmod_poly_normalise (buf);
1965
1966    result += convertnmod_poly_t2FacCF (buf, x)*power (y, i);
1967    i++;
1968    k= d*i;
1969    nmod_poly_clear (buf);
1970  }
1971
1972  return result;
1973}
1974
1975CanonicalForm
1976mulMod2FLINTFpReci (const CanonicalForm& F, const CanonicalForm& G, const
1977                    CanonicalForm& M)
1978{
1979  int d1= degree (F, 1) + degree (G, 1) + 1;
1980  d1 /= 2;
1981  d1 += 1;
1982
1983  nmod_poly_t F1, F2;
1984  kronSubReciproFp (F1, F2, F, d1);
1985
1986  nmod_poly_t G1, G2;
1987  kronSubReciproFp (G1, G2, G, d1);
1988
1989  int k= d1*degree (M);
1990  nmod_poly_mullow (F1, F1, G1, (long) k);
1991
1992  int degtailF= degree (tailcoeff (F), 1);;
1993  int degtailG= degree (tailcoeff (G), 1);
1994  int taildegF= taildegree (F);
1995  int taildegG= taildegree (G);
1996
1997  int b= nmod_poly_degree (F2) + nmod_poly_degree (G2) - k - degtailF - degtailG
1998         + d1*(2+taildegF + taildegG);
1999  nmod_poly_mulhigh (F2, F2, G2, b);
2000  nmod_poly_shift_right (F2, F2, b);
2001  int d2= tmax (nmod_poly_degree (F2)/d1, nmod_poly_degree (F1)/d1);
2002
2003
2004  CanonicalForm result= reverseSubstReciproFp (F1, F2, d1, d2);
2005
2006  nmod_poly_clear (F1);
2007  nmod_poly_clear (F2);
2008  nmod_poly_clear (G1);
2009  nmod_poly_clear (G2);
2010  return result;
2011}
2012
2013CanonicalForm
2014mulMod2FLINTFp (const CanonicalForm& F, const CanonicalForm& G, const
2015                CanonicalForm& M)
2016{
2017  CanonicalForm A= F;
2018  CanonicalForm B= G;
2019
2020  int degAx= degree (A, 1);
2021  int degAy= degree (A, 2);
2022  int degBx= degree (B, 1);
2023  int degBy= degree (B, 2);
2024  int d1= degAx + 1 + degBx;
2025  int d2= tmax (degAy, degBy);
2026
2027  if (d1 > 128 && d2 > 160 && (degAy == degBy) && (2*degAy > degree (M)))
2028    return mulMod2FLINTFpReci (A, B, M);
2029
2030  nmod_poly_t FLINTA, FLINTB;
2031  kronSubFp (FLINTA, A, d1);
2032  kronSubFp (FLINTB, B, d1);
2033
2034  int k= d1*degree (M);
2035  nmod_poly_mullow (FLINTA, FLINTA, FLINTB, (long) k);
2036
2037  A= reverseSubstFp (FLINTA, d1);
2038
2039  nmod_poly_clear (FLINTA);
2040  nmod_poly_clear (FLINTB);
2041  return A;
2042}
2043
2044#if ( __FLINT_RELEASE >= 20400)
2045CanonicalForm
2046mulMod2FLINTFqReci (const CanonicalForm& F, const CanonicalForm& G, const
2047                    CanonicalForm& M, const Variable& alpha,
2048                    const fq_nmod_ctx_t fq_con)
2049{
2050  int d1= degree (F, 1) + degree (G, 1) + 1;
2051  d1 /= 2;
2052  d1 += 1;
2053
2054  fq_nmod_poly_t F1, F2;
2055  kronSubReciproFq (F1, F2, F, d1, fq_con);
2056
2057  fq_nmod_poly_t G1, G2;
2058  kronSubReciproFq (G1, G2, G, d1, fq_con);
2059
2060  int k= d1*degree (M);
2061  fq_nmod_poly_mullow (F1, F1, G1, (long) k, fq_con);
2062
2063  int degtailF= degree (tailcoeff (F), 1);
2064  int degtailG= degree (tailcoeff (G), 1);
2065  int taildegF= taildegree (F);
2066  int taildegG= taildegree (G);
2067
2068  int b= k + degtailF + degtailG - d1*(2+taildegF + taildegG);
2069
2070  fq_nmod_poly_reverse (F2, F2, fq_nmod_poly_length (F2, fq_con), fq_con);
2071  fq_nmod_poly_reverse (G2, G2, fq_nmod_poly_length (G2, fq_con), fq_con);
2072  fq_nmod_poly_mullow (F2, F2, G2, b+1, fq_con);
2073  fq_nmod_poly_reverse (F2, F2, b+1, fq_con);
2074
2075  int d2= tmax (fq_nmod_poly_degree (F2, fq_con)/d1,
2076                fq_nmod_poly_degree (F1, fq_con)/d1);
2077
2078  CanonicalForm result= reverseSubstReciproFq (F1, F2, d1, d2, alpha, fq_con);
2079
2080  fq_nmod_poly_clear (F1, fq_con);
2081  fq_nmod_poly_clear (F2, fq_con);
2082  fq_nmod_poly_clear (G1, fq_con);
2083  fq_nmod_poly_clear (G2, fq_con);
2084  return result;
2085}
2086
2087CanonicalForm
2088mulMod2FLINTFq (const CanonicalForm& F, const CanonicalForm& G, const
2089                CanonicalForm& M, const Variable& alpha,
2090                const fq_nmod_ctx_t fq_con)
2091{
2092  CanonicalForm A= F;
2093  CanonicalForm B= G;
2094
2095  int degAx= degree (A, 1);
2096  int degAy= degree (A, 2);
2097  int degBx= degree (B, 1);
2098  int degBy= degree (B, 2);
2099  int d1= degAx + 1 + degBx;
2100  int d2= tmax (degAy, degBy);
2101
2102  if (d1 > 128 && d2 > 160 && (degAy == degBy) && (2*degAy > degree (M)))
2103    return mulMod2FLINTFqReci (A, B, M, alpha, fq_con);
2104
2105  fq_nmod_poly_t FLINTA, FLINTB;
2106  kronSubFq (FLINTA, A, d1, fq_con);
2107  kronSubFq (FLINTB, B, d1, fq_con);
2108
2109  int k= d1*degree (M);
2110  fq_nmod_poly_mullow (FLINTA, FLINTA, FLINTB, (long) k, fq_con);
2111
2112  A= reverseSubstFq (FLINTA, d1, alpha, fq_con);
2113
2114  fq_nmod_poly_clear (FLINTA, fq_con);
2115  fq_nmod_poly_clear (FLINTB, fq_con);
2116  return A;
2117}
2118#endif
2119
2120CanonicalForm
2121mulMod2FLINTQReci (const CanonicalForm& F, const CanonicalForm& G, const
2122                    CanonicalForm& M)
2123{
2124  int d1= degree (F, 1) + degree (G, 1) + 1;
2125  d1 /= 2;
2126  d1 += 1;
2127
2128  fmpz_poly_t F1, F2;
2129  kronSubReciproQ (F1, F2, F, d1);
2130
2131  fmpz_poly_t G1, G2;
2132  kronSubReciproQ (G1, G2, G, d1);
2133
2134  int k= d1*degree (M);
2135  fmpz_poly_mullow (F1, F1, G1, (long) k);
2136
2137  int degtailF= degree (tailcoeff (F), 1);;
2138  int degtailG= degree (tailcoeff (G), 1);
2139  int taildegF= taildegree (F);
2140  int taildegG= taildegree (G);
2141
2142  int b= fmpz_poly_degree (F2) + fmpz_poly_degree (G2) - k - degtailF - degtailG
2143         + d1*(2+taildegF + taildegG);
2144  fmpz_poly_mulhigh_n (F2, F2, G2, b);
2145  fmpz_poly_shift_right (F2, F2, b);
2146  int d2= tmax (fmpz_poly_degree (F2)/d1, fmpz_poly_degree (F1)/d1);
2147
2148  CanonicalForm result= reverseSubstReciproQ (F1, F2, d1, d2);
2149
2150  fmpz_poly_clear (F1);
2151  fmpz_poly_clear (F2);
2152  fmpz_poly_clear (G1);
2153  fmpz_poly_clear (G2);
2154  return result;
2155}
2156
2157CanonicalForm
2158mulMod2FLINTQ (const CanonicalForm& F, const CanonicalForm& G, const
2159                CanonicalForm& M)
2160{
2161  CanonicalForm A= F;
2162  CanonicalForm B= G;
2163
2164  int degAx= degree (A, 1);
2165  int degBx= degree (B, 1);
2166  int d1= degAx + 1 + degBx;
2167
2168  CanonicalForm f= bCommonDen (F);
2169  CanonicalForm g= bCommonDen (G);
2170  A *= f;
2171  B *= g;
2172
2173  fmpz_poly_t FLINTA, FLINTB;
2174  kronSubQa (FLINTA, A, d1);
2175  kronSubQa (FLINTB, B, d1);
2176  int k= d1*degree (M);
2177
2178  fmpz_poly_mullow (FLINTA, FLINTA, FLINTB, (long) k);
2179  A= reverseSubstQ (FLINTA, d1);
2180  fmpz_poly_clear (FLINTA);
2181  fmpz_poly_clear (FLINTB);
2182  return A/(f*g);
2183}
2184
2185/*CanonicalForm
2186mulMod2FLINTQa (const CanonicalForm& F, const CanonicalForm& G,
2187                const CanonicalForm& M)
2188{
2189  Variable a;
2190  if (!hasFirstAlgVar (F,a) && !hasFirstAlgVar (G, a))
2191    return mulMod2FLINTQ (F, G, M);
2192  CanonicalForm A= F;
2193
2194  int degFx= degree (F, 1);
2195  int degFa= degree (F, a);
2196  int degGx= degree (G, 1);
2197  int degGa= degree (G, a);
2198
2199  int d2= degFa+degGa+1;
2200  int d1= degFx + 1 + degGx;
2201  d1 *= d2;
2202
2203  fmpq_poly_t FLINTF, FLINTG;
2204  kronSubQa (FLINTF, F, d1, d2);
2205  kronSubQa (FLINTG, G, d1, d2);
2206
2207  fmpq_poly_mullow (FLINTF, FLINTF, FLINTG, d1*degree (M));
2208
2209  fmpq_poly_t mipo;
2210  convertFacCF2Fmpq_poly_t (mipo, getMipo (a));
2211  CanonicalForm result= reverseSubstQa (FLINTF, d1, d2, a, mipo);
2212  fmpq_poly_clear (FLINTF);
2213  fmpq_poly_clear (FLINTG);
2214  return result;
2215}*/
2216
2217CanonicalForm
2218mulMod2FLINTQa (const CanonicalForm& F, const CanonicalForm& G,
2219                const CanonicalForm& M)
2220{
2221  Variable a;
2222  if (!hasFirstAlgVar (F,a) && !hasFirstAlgVar (G, a))
2223    return mulMod2FLINTQ (F, G, M);
2224  CanonicalForm A= F, B= G;
2225
2226  int degFx= degree (F, 1);
2227  int degFa= degree (F, a);
2228  int degGx= degree (G, 1);
2229  int degGa= degree (G, a);
2230
2231  int d2= degFa+degGa+1;
2232  int d1= degFx + 1 + degGx;
2233  d1 *= d2;
2234
2235  CanonicalForm f= bCommonDen (F);
2236  CanonicalForm g= bCommonDen (G);
2237  A *= f;
2238  B *= g;
2239
2240  fmpz_poly_t FLINTF, FLINTG;
2241  kronSubQa (FLINTF, A, d1, d2);
2242  kronSubQa (FLINTG, B, d1, d2);
2243
2244  fmpz_poly_mullow (FLINTF, FLINTF, FLINTG, d1*degree (M));
2245
2246  fmpq_poly_t mipo;
2247  convertFacCF2Fmpq_poly_t (mipo, getMipo (a));
2248  A= reverseSubstQa (FLINTF, d1, d2, a, mipo);
2249  fmpz_poly_clear (FLINTF);
2250  fmpz_poly_clear (FLINTG);
2251  return A/(f*g);
2252}
2253
2254#endif
2255
2256#ifndef HAVE_FLINT
2257zz_pX kronSubFp (const CanonicalForm& A, int d)
2258{
2259  int degAy= degree (A);
2260  zz_pX result;
2261  result.rep.SetLength (d*(degAy + 1));
2262
2263  zz_p *resultp;
2264  resultp= result.rep.elts();
2265  zz_pX buf;
2266  zz_p *bufp;
2267  int j, k, bufRepLength;
2268
2269  for (CFIterator i= A; i.hasTerms(); i++)
2270  {
2271    if (i.coeff().inCoeffDomain())
2272      buf= convertFacCF2NTLzzpX (i.coeff());
2273    else
2274      buf= convertFacCF2NTLzzpX (i.coeff());
2275
2276    k= i.exp()*d;
2277    bufp= buf.rep.elts();
2278    bufRepLength= (int) buf.rep.length();
2279    for (j= 0; j < bufRepLength; j++)
2280      resultp [j + k]= bufp [j];
2281  }
2282  result.normalize();
2283
2284  return result;
2285}
2286#endif
2287
2288#if (!(HAVE_FLINT &&  __FLINT_RELEASE >= 20400))
2289zz_pEX kronSubFq (const CanonicalForm& A, int d, const Variable& alpha)
2290{
2291  int degAy= degree (A);
2292  zz_pEX result;
2293  result.rep.SetLength (d*(degAy + 1));
2294
2295  Variable v;
2296  zz_pE *resultp;
2297  resultp= result.rep.elts();
2298  zz_pEX buf1;
2299  zz_pE *buf1p;
2300  zz_pX buf2;
2301  zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
2302  int j, k, buf1RepLength;
2303
2304  for (CFIterator i= A; i.hasTerms(); i++)
2305  {
2306    if (i.coeff().inCoeffDomain())
2307    {
2308      buf2= convertFacCF2NTLzzpX (i.coeff());
2309      buf1= to_zz_pEX (to_zz_pE (buf2));
2310    }
2311    else
2312      buf1= convertFacCF2NTLzz_pEX (i.coeff(), NTLMipo);
2313
2314    k= i.exp()*d;
2315    buf1p= buf1.rep.elts();
2316    buf1RepLength= (int) buf1.rep.length();
2317    for (j= 0; j < buf1RepLength; j++)
2318      resultp [j + k]= buf1p [j];
2319  }
2320  result.normalize();
2321
2322  return result;
2323}
2324
2325void
2326kronSubReciproFq (zz_pEX& subA1, zz_pEX& subA2,const CanonicalForm& A, int d,
2327                  const Variable& alpha)
2328{
2329  int degAy= degree (A);
2330  subA1.rep.SetLength ((long) d*(degAy + 2));
2331  subA2.rep.SetLength ((long) d*(degAy + 2));
2332
2333  Variable v;
2334  zz_pE *subA1p;
2335  zz_pE *subA2p;
2336  subA1p= subA1.rep.elts();
2337  subA2p= subA2.rep.elts();
2338  zz_pEX buf;
2339  zz_pE *bufp;
2340  zz_pX buf2;
2341  zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
2342  int j, k, kk, bufRepLength;
2343
2344  for (CFIterator i= A; i.hasTerms(); i++)
2345  {
2346    if (i.coeff().inCoeffDomain())
2347    {
2348      buf2= convertFacCF2NTLzzpX (i.coeff());
2349      buf= to_zz_pEX (to_zz_pE (buf2));
2350    }
2351    else
2352      buf= convertFacCF2NTLzz_pEX (i.coeff(), NTLMipo);
2353
2354    k= i.exp()*d;
2355    kk= (degAy - i.exp())*d;
2356    bufp= buf.rep.elts();
2357    bufRepLength= (int) buf.rep.length();
2358    for (j= 0; j < bufRepLength; j++)
2359    {
2360      subA1p [j + k] += bufp [j];
2361      subA2p [j + kk] += bufp [j];
2362    }
2363  }
2364  subA1.normalize();
2365  subA2.normalize();
2366}
2367#endif
2368
2369#ifndef HAVE_FLINT
2370void
2371kronSubReciproFp (zz_pX& subA1, zz_pX& subA2, const CanonicalForm& A, int d)
2372{
2373  int degAy= degree (A);
2374  subA1.rep.SetLength ((long) d*(degAy + 2));
2375  subA2.rep.SetLength ((long) d*(degAy + 2));
2376
2377  zz_p *subA1p;
2378  zz_p *subA2p;
2379  subA1p= subA1.rep.elts();
2380  subA2p= subA2.rep.elts();
2381  zz_pX buf;
2382  zz_p *bufp;
2383  int j, k, kk, bufRepLength;
2384
2385  for (CFIterator i= A; i.hasTerms(); i++)
2386  {
2387    buf= convertFacCF2NTLzzpX (i.coeff());
2388
2389    k= i.exp()*d;
2390    kk= (degAy - i.exp())*d;
2391    bufp= buf.rep.elts();
2392    bufRepLength= (int) buf.rep.length();
2393    for (j= 0; j < bufRepLength; j++)
2394    {
2395      subA1p [j + k] += bufp [j];
2396      subA2p [j + kk] += bufp [j];
2397    }
2398  }
2399  subA1.normalize();
2400  subA2.normalize();
2401}
2402#endif
2403
2404#if (!(HAVE_FLINT &&  __FLINT_RELEASE >= 20400))
2405CanonicalForm
2406reverseSubstReciproFq (const zz_pEX& F, const zz_pEX& G, int d, int k,
2407                       const Variable& alpha)
2408{
2409  Variable y= Variable (2);
2410  Variable x= Variable (1);
2411
2412  zz_pEX f= F;
2413  zz_pEX g= G;
2414  int degf= deg(f);
2415  int degg= deg(g);
2416
2417  zz_pEX buf1;
2418  zz_pEX buf2;
2419  zz_pEX buf3;
2420
2421  zz_pE *buf1p;
2422  zz_pE *buf2p;
2423  zz_pE *buf3p;
2424  if (f.rep.length() < (long) d*(k+1)) //zero padding
2425    f.rep.SetLength ((long)d*(k+1));
2426
2427  zz_pE *gp= g.rep.elts();
2428  zz_pE *fp= f.rep.elts();
2429  CanonicalForm result= 0;
2430  int i= 0;
2431  int lf= 0;
2432  int lg= d*k;
2433  int degfSubLf= degf;
2434  int deggSubLg= degg-lg;
2435  int repLengthBuf2, repLengthBuf1, ind, tmp;
2436  zz_pE zzpEZero= zz_pE();
2437
2438  while (degf >= lf || lg >= 0)
2439  {
2440    if (degfSubLf >= d)
2441      repLengthBuf1= d;
2442    else if (degfSubLf < 0)
2443      repLengthBuf1= 0;
2444    else
2445      repLengthBuf1= degfSubLf + 1;
2446    buf1.rep.SetLength((long) repLengthBuf1);
2447
2448    buf1p= buf1.rep.elts();
2449    for (ind= 0; ind < repLengthBuf1; ind++)
2450      buf1p [ind]= fp [ind + lf];
2451    buf1.normalize();
2452
2453    repLengthBuf1= buf1.rep.length();
2454
2455    if (deggSubLg >= d - 1)
2456      repLengthBuf2= d - 1;
2457    else if (deggSubLg < 0)
2458      repLengthBuf2= 0;
2459    else
2460      repLengthBuf2= deggSubLg + 1;
2461
2462    buf2.rep.SetLength ((long) repLengthBuf2);
2463    buf2p= buf2.rep.elts();
2464    for (ind= 0; ind < repLengthBuf2; ind++)
2465      buf2p [ind]= gp [ind + lg];
2466    buf2.normalize();
2467
2468    repLengthBuf2= buf2.rep.length();
2469
2470    buf3.rep.SetLength((long) repLengthBuf2 + d);
2471    buf3p= buf3.rep.elts();
2472    buf2p= buf2.rep.elts();
2473    buf1p= buf1.rep.elts();
2474    for (ind= 0; ind < repLengthBuf1; ind++)
2475      buf3p [ind]= buf1p [ind];
2476    for (ind= repLengthBuf1; ind < d; ind++)
2477      buf3p [ind]= zzpEZero;
2478    for (ind= 0; ind < repLengthBuf2; ind++)
2479      buf3p [ind + d]= buf2p [ind];
2480    buf3.normalize();
2481
2482    result += convertNTLzz_pEX2CF (buf3, x, alpha)*power (y, i);
2483    i++;
2484
2485
2486    lf= i*d;
2487    degfSubLf= degf - lf;
2488
2489    lg= d*(k-i);
2490    deggSubLg= degg - lg;
2491
2492    buf1p= buf1.rep.elts();
2493
2494    if (lg >= 0 && deggSubLg > 0)
2495    {
2496      if (repLengthBuf2 > degfSubLf + 1)
2497        degfSubLf= repLengthBuf2 - 1;
2498      tmp= tmin (repLengthBuf1, deggSubLg + 1);
2499      for (ind= 0; ind < tmp; ind++)
2500        gp [ind + lg] -= buf1p [ind];
2501    }
2502
2503    if (lg < 0)
2504      break;
2505
2506    buf2p= buf2.rep.elts();
2507    if (degfSubLf >= 0)
2508    {
2509      for (ind= 0; ind < repLengthBuf2; ind++)
2510        fp [ind + lf] -= buf2p [ind];
2511    }
2512  }
2513
2514  return result;
2515}
2516#endif
2517
2518#ifndef HAVE_FLINT
2519CanonicalForm
2520reverseSubstReciproFp (const zz_pX& F, const zz_pX& G, int d, int k)
2521{
2522  Variable y= Variable (2);
2523  Variable x= Variable (1);
2524
2525  zz_pX f= F;
2526  zz_pX g= G;
2527  int degf= deg(f);
2528  int degg= deg(g);
2529
2530  zz_pX buf1;
2531  zz_pX buf2;
2532  zz_pX buf3;
2533
2534  zz_p *buf1p;
2535  zz_p *buf2p;
2536  zz_p *buf3p;
2537
2538  if (f.rep.length() < (long) d*(k+1)) //zero padding
2539    f.rep.SetLength ((long)d*(k+1));
2540
2541  zz_p *gp= g.rep.elts();
2542  zz_p *fp= f.rep.elts();
2543  CanonicalForm result= 0;
2544  int i= 0;
2545  int lf= 0;
2546  int lg= d*k;
2547  int degfSubLf= degf;
2548  int deggSubLg= degg-lg;
2549  int repLengthBuf2, repLengthBuf1, ind, tmp;
2550  zz_p zzpZero= zz_p();
2551  while (degf >= lf || lg >= 0)
2552  {
2553    if (degfSubLf >= d)
2554      repLengthBuf1= d;
2555    else if (degfSubLf < 0)
2556      repLengthBuf1= 0;
2557    else
2558      repLengthBuf1= degfSubLf + 1;
2559    buf1.rep.SetLength((long) repLengthBuf1);
2560
2561    buf1p= buf1.rep.elts();
2562    for (ind= 0; ind < repLengthBuf1; ind++)
2563      buf1p [ind]= fp [ind + lf];
2564    buf1.normalize();
2565
2566    repLengthBuf1= buf1.rep.length();
2567
2568    if (deggSubLg >= d - 1)
2569      repLengthBuf2= d - 1;
2570    else if (deggSubLg < 0)
2571      repLengthBuf2= 0;
2572    else
2573      repLengthBuf2= deggSubLg + 1;
2574
2575    buf2.rep.SetLength ((long) repLengthBuf2);
2576    buf2p= buf2.rep.elts();
2577    for (ind= 0; ind < repLengthBuf2; ind++)
2578      buf2p [ind]= gp [ind + lg];
2579
2580    buf2.normalize();
2581
2582    repLengthBuf2= buf2.rep.length();
2583
2584
2585    buf3.rep.SetLength((long) repLengthBuf2 + d);
2586    buf3p= buf3.rep.elts();
2587    buf2p= buf2.rep.elts();
2588    buf1p= buf1.rep.elts();
2589    for (ind= 0; ind < repLengthBuf1; ind++)
2590      buf3p [ind]= buf1p [ind];
2591    for (ind= repLengthBuf1; ind < d; ind++)
2592      buf3p [ind]= zzpZero;
2593    for (ind= 0; ind < repLengthBuf2; ind++)
2594      buf3p [ind + d]= buf2p [ind];
2595    buf3.normalize();
2596
2597    result += convertNTLzzpX2CF (buf3, x)*power (y, i);
2598    i++;
2599
2600
2601    lf= i*d;
2602    degfSubLf= degf - lf;
2603
2604    lg= d*(k-i);
2605    deggSubLg= degg - lg;
2606
2607    buf1p= buf1.rep.elts();
2608
2609    if (lg >= 0 && deggSubLg > 0)
2610    {
2611      if (repLengthBuf2 > degfSubLf + 1)
2612        degfSubLf= repLengthBuf2 - 1;
2613      tmp= tmin (repLengthBuf1, deggSubLg + 1);
2614      for (ind= 0; ind < tmp; ind++)
2615        gp [ind + lg] -= buf1p [ind];
2616    }
2617    if (lg < 0)
2618      break;
2619
2620    buf2p= buf2.rep.elts();
2621    if (degfSubLf >= 0)
2622    {
2623      for (ind= 0; ind < repLengthBuf2; ind++)
2624        fp [ind + lf] -= buf2p [ind];
2625    }
2626  }
2627
2628  return result;
2629}
2630#endif
2631
2632#if (!(HAVE_FLINT &&  __FLINT_RELEASE >= 20400))
2633CanonicalForm reverseSubstFq (const zz_pEX& F, int d, const Variable& alpha)
2634{
2635  Variable y= Variable (2);
2636  Variable x= Variable (1);
2637
2638  zz_pEX f= F;
2639  zz_pE *fp= f.rep.elts();
2640
2641  zz_pEX buf;
2642  zz_pE *bufp;
2643  CanonicalForm result= 0;
2644  int i= 0;
2645  int degf= deg(f);
2646  int k= 0;
2647  int degfSubK, repLength, j;
2648  while (degf >= k)
2649  {
2650    degfSubK= degf - k;
2651    if (degfSubK >= d)
2652      repLength= d;
2653    else
2654      repLength= degfSubK + 1;
2655
2656    buf.rep.SetLength ((long) repLength);
2657    bufp= buf.rep.elts();
2658    for (j= 0; j < repLength; j++)
2659      bufp [j]= fp [j + k];
2660    buf.normalize();
2661
2662    result += convertNTLzz_pEX2CF (buf, x, alpha)*power (y, i);
2663    i++;
2664    k= d*i;
2665  }
2666
2667  return result;
2668}
2669#endif
2670
2671#ifndef HAVE_FLINT
2672CanonicalForm reverseSubstFp (const zz_pX& F, int d)
2673{
2674  Variable y= Variable (2);
2675  Variable x= Variable (1);
2676
2677  zz_pX f= F;
2678  zz_p *fp= f.rep.elts();
2679
2680  zz_pX buf;
2681  zz_p *bufp;
2682  CanonicalForm result= 0;
2683  int i= 0;
2684  int degf= deg(f);
2685  int k= 0;
2686  int degfSubK, repLength, j;
2687  while (degf >= k)
2688  {
2689    degfSubK= degf - k;
2690    if (degfSubK >= d)
2691      repLength= d;
2692    else
2693      repLength= degfSubK + 1;
2694
2695    buf.rep.SetLength ((long) repLength);
2696    bufp= buf.rep.elts();
2697    for (j= 0; j < repLength; j++)
2698      bufp [j]= fp [j + k];
2699    buf.normalize();
2700
2701    result += convertNTLzzpX2CF (buf, x)*power (y, i);
2702    i++;
2703    k= d*i;
2704  }
2705
2706  return result;
2707}
2708
2709// assumes input to be reduced mod M and to be an element of Fp
2710CanonicalForm
2711mulMod2NTLFpReci (const CanonicalForm& F, const CanonicalForm& G, const
2712                  CanonicalForm& M)
2713{
2714  int d1= degree (F, 1) + degree (G, 1) + 1;
2715  d1 /= 2;
2716  d1 += 1;
2717
2718  zz_pX F1, F2;
2719  kronSubReciproFp (F1, F2, F, d1);
2720  zz_pX G1, G2;
2721  kronSubReciproFp (G1, G2, G, d1);
2722
2723  int k= d1*degree (M);
2724  MulTrunc (F1, F1, G1, (long) k);
2725
2726  int degtailF= degree (tailcoeff (F), 1);
2727  int degtailG= degree (tailcoeff (G), 1);
2728  int taildegF= taildegree (F);
2729  int taildegG= taildegree (G);
2730  int b= k + degtailF + degtailG - d1*(2+taildegF+taildegG);
2731
2732  reverse (F2, F2);
2733  reverse (G2, G2);
2734  MulTrunc (F2, F2, G2, b + 1);
2735  reverse (F2, F2, b);
2736
2737  int d2= tmax (deg (F2)/d1, deg (F1)/d1);
2738  return reverseSubstReciproFp (F1, F2, d1, d2);
2739}
2740
2741//Kronecker substitution
2742CanonicalForm
2743mulMod2NTLFp (const CanonicalForm& F, const CanonicalForm& G, const
2744              CanonicalForm& M)
2745{
2746  CanonicalForm A= F;
2747  CanonicalForm B= G;
2748
2749  int degAx= degree (A, 1);
2750  int degAy= degree (A, 2);
2751  int degBx= degree (B, 1);
2752  int degBy= degree (B, 2);
2753  int d1= degAx + 1 + degBx;
2754  int d2= tmax (degAy, degBy);
2755
2756  if (d1 > 128 && d2 > 160 && (degAy == degBy) && (2*degAy > degree (M)))
2757    return mulMod2NTLFpReci (A, B, M);
2758
2759  zz_pX NTLA= kronSubFp (A, d1);
2760  zz_pX NTLB= kronSubFp (B, d1);
2761
2762  int k= d1*degree (M);
2763  MulTrunc (NTLA, NTLA, NTLB, (long) k);
2764
2765  A= reverseSubstFp (NTLA, d1);
2766
2767  return A;
2768}
2769#endif
2770
2771#if (!(HAVE_FLINT &&  __FLINT_RELEASE >= 20400))
2772// assumes input to be reduced mod M and to be an element of Fq not Fp
2773CanonicalForm
2774mulMod2NTLFqReci (const CanonicalForm& F, const CanonicalForm& G, const
2775                  CanonicalForm& M, const Variable& alpha)
2776{
2777  int d1= degree (F, 1) + degree (G, 1) + 1;
2778  d1 /= 2;
2779  d1 += 1;
2780
2781  zz_pEX F1, F2;
2782  kronSubReciproFq (F1, F2, F, d1, alpha);
2783  zz_pEX G1, G2;
2784  kronSubReciproFq (G1, G2, G, d1, alpha);
2785
2786  int k= d1*degree (M);
2787  MulTrunc (F1, F1, G1, (long) k);
2788
2789  int degtailF= degree (tailcoeff (F), 1);
2790  int degtailG= degree (tailcoeff (G), 1);
2791  int taildegF= taildegree (F);
2792  int taildegG= taildegree (G);
2793  int b= k + degtailF + degtailG - d1*(2+taildegF+taildegG);
2794
2795  reverse (F2, F2);
2796  reverse (G2, G2);
2797  MulTrunc (F2, F2, G2, b + 1);
2798  reverse (F2, F2, b);
2799
2800  int d2= tmax (deg (F2)/d1, deg (F1)/d1);
2801  return reverseSubstReciproFq (F1, F2, d1, d2, alpha);
2802}
2803#endif
2804
2805#ifdef HAVE_FLINT
2806CanonicalForm
2807mulMod2FLINTFp (const CanonicalForm& F, const CanonicalForm& G, const
2808                CanonicalForm& M);
2809#endif
2810
2811CanonicalForm
2812mulMod2NTLFq (const CanonicalForm& F, const CanonicalForm& G, const
2813              CanonicalForm& M)
2814{
2815  Variable alpha;
2816  CanonicalForm A= F;
2817  CanonicalForm B= G;
2818
2819  if (hasFirstAlgVar (A, alpha) || hasFirstAlgVar (B, alpha))
2820  {
2821#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
2822    nmod_poly_t FLINTmipo;
2823    convertFacCF2nmod_poly_t (FLINTmipo, getMipo (alpha));
2824
2825    fq_nmod_ctx_t fq_con;
2826    fq_nmod_ctx_init_modulus (fq_con, FLINTmipo, "Z");
2827
2828    A= mulMod2FLINTFq (A, B, M, alpha, fq_con);
2829    nmod_poly_clear (FLINTmipo);
2830    fq_nmod_ctx_clear (fq_con);
2831#else
2832    int degAx= degree (A, 1);
2833    int degAy= degree (A, 2);
2834    int degBx= degree (B, 1);
2835    int degBy= degree (B, 2);
2836    int d1= degAx + degBx + 1;
2837    int d2= tmax (degAy, degBy);
2838    if (fac_NTL_char != getCharacteristic())
2839    {
2840      fac_NTL_char= getCharacteristic();
2841      zz_p::init (getCharacteristic());
2842    }
2843    zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
2844    zz_pE::init (NTLMipo);
2845
2846    int degMipo= degree (getMipo (alpha));
2847    if ((d1 > 128/degMipo) && (d2 > 160/degMipo) && (degAy == degBy) &&
2848        (2*degAy > degree (M)))
2849      return mulMod2NTLFqReci (A, B, M, alpha);
2850
2851    zz_pEX NTLA= kronSubFq (A, d1, alpha);
2852    zz_pEX NTLB= kronSubFq (B, d1, alpha);
2853
2854    int k= d1*degree (M);
2855
2856    MulTrunc (NTLA, NTLA, NTLB, (long) k);
2857
2858    A= reverseSubstFq (NTLA, d1, alpha);
2859#endif
2860  }
2861  else
2862  {
2863#ifdef HAVE_FLINT
2864    A= mulMod2FLINTFp (A, B, M);
2865#else
2866    A= mulMod2NTLFp (A, B, M);
2867#endif
2868  }
2869  return A;
2870}
2871
2872CanonicalForm mulMod2 (const CanonicalForm& A, const CanonicalForm& B,
2873                       const CanonicalForm& M)
2874{
2875  if (A.isZero() || B.isZero())
2876    return 0;
2877
2878  ASSERT (M.isUnivariate(), "M must be univariate");
2879
2880  CanonicalForm F= mod (A, M);
2881  CanonicalForm G= mod (B, M);
2882  if (F.inCoeffDomain())
2883    return G*F;
2884  if (G.inCoeffDomain())
2885    return F*G;
2886
2887  Variable y= M.mvar();
2888  int degF= degree (F, y);
2889  int degG= degree (G, y);
2890
2891  if ((degF < 1 && degG < 1) && (F.isUnivariate() && G.isUnivariate()) &&
2892      (F.level() == G.level()))
2893  {
2894    CanonicalForm result= mulNTL (F, G);
2895    return mod (result, M);
2896  }
2897  else if (degF <= 1 && degG <= 1)
2898  {
2899    CanonicalForm result= F*G;
2900    return mod (result, M);
2901  }
2902
2903  int sizeF= size (F);
2904  int sizeG= size (G);
2905
2906  int fallBackToNaive= 50;
2907  if (sizeF < fallBackToNaive || sizeG < fallBackToNaive)
2908  {
2909    if (sizeF < sizeG)
2910      return mod (G*F, M);
2911    else
2912      return mod (F*G, M);
2913  }
2914
2915#ifdef HAVE_FLINT
2916  if (getCharacteristic() == 0)
2917    return mulMod2FLINTQa (F, G, M);
2918#endif
2919
2920  if (getCharacteristic() > 0 && CFFactory::gettype() != GaloisFieldDomain &&
2921      (((degF-degG) < 50 && degF > degG) || ((degG-degF) < 50 && degF <= degG)))
2922    return mulMod2NTLFq (F, G, M);
2923
2924  int m= (int) ceil (degree (M)/2.0);
2925  if (degF >= m || degG >= m)
2926  {
2927    CanonicalForm MLo= power (y, m);
2928    CanonicalForm MHi= power (y, degree (M) - m);
2929    CanonicalForm F0= mod (F, MLo);
2930    CanonicalForm F1= div (F, MLo);
2931    CanonicalForm G0= mod (G, MLo);
2932    CanonicalForm G1= div (G, MLo);
2933    CanonicalForm F0G1= mulMod2 (F0, G1, MHi);
2934    CanonicalForm F1G0= mulMod2 (F1, G0, MHi);
2935    CanonicalForm F0G0= mulMod2 (F0, G0, M);
2936    return F0G0 + MLo*(F0G1 + F1G0);
2937  }
2938  else
2939  {
2940    m= (int) ceil (tmax (degF, degG)/2.0);
2941    CanonicalForm yToM= power (y, m);
2942    CanonicalForm F0= mod (F, yToM);
2943    CanonicalForm F1= div (F, yToM);
2944    CanonicalForm G0= mod (G, yToM);
2945    CanonicalForm G1= div (G, yToM);
2946    CanonicalForm H00= mulMod2 (F0, G0, M);
2947    CanonicalForm H11= mulMod2 (F1, G1, M);
2948    CanonicalForm H01= mulMod2 (F0 + F1, G0 + G1, M);
2949    return H11*yToM*yToM + (H01 - H11 - H00)*yToM + H00;
2950  }
2951  DEBOUTLN (cerr, "fatal end in mulMod2");
2952}
2953
2954// end bivariate polys
2955//**********************
2956// multivariate polys
2957
2958CanonicalForm mod (const CanonicalForm& F, const CFList& M)
2959{
2960  CanonicalForm A= F;
2961  for (CFListIterator i= M; i.hasItem(); i++)
2962    A= mod (A, i.getItem());
2963  return A;
2964}
2965
2966CanonicalForm mulMod (const CanonicalForm& A, const CanonicalForm& B,
2967                      const CFList& MOD)
2968{
2969  if (A.isZero() || B.isZero())
2970    return 0;
2971
2972  if (MOD.length() == 1)
2973    return mulMod2 (A, B, MOD.getLast());
2974
2975  CanonicalForm M= MOD.getLast();
2976  CanonicalForm F= mod (A, M);
2977  CanonicalForm G= mod (B, M);
2978  if (F.inCoeffDomain())
2979    return G*F;
2980  if (G.inCoeffDomain())
2981    return F*G;
2982
2983  int sizeF= size (F);
2984  int sizeG= size (G);
2985
2986  if (sizeF / MOD.length() < 100 || sizeG / MOD.length() < 100)
2987  {
2988    if (sizeF < sizeG)
2989      return mod (G*F, MOD);
2990    else
2991      return mod (F*G, MOD);
2992  }
2993
2994  Variable y= M.mvar();
2995  int degF= degree (F, y);
2996  int degG= degree (G, y);
2997
2998  if ((degF <= 1 && F.level() <= M.level()) &&
2999      (degG <= 1 && G.level() <= M.level()))
3000  {
3001    CFList buf= MOD;
3002    buf.removeLast();
3003    if (degF == 1 && degG == 1)
3004    {
3005      CanonicalForm F0= mod (F, y);
3006      CanonicalForm F1= div (F, y);
3007      CanonicalForm G0= mod (G, y);
3008      CanonicalForm G1= div (G, y);
3009      if (degree (M) > 2)
3010      {
3011        CanonicalForm H00= mulMod (F0, G0, buf);
3012        CanonicalForm H11= mulMod (F1, G1, buf);
3013        CanonicalForm H01= mulMod (F0 + F1, G0 + G1, buf);
3014        return H11*y*y + (H01 - H00 - H11)*y + H00;
3015      }
3016      else //here degree (M) == 2
3017      {
3018        buf.append (y);
3019        CanonicalForm F0G1= mulMod (F0, G1, buf);
3020        CanonicalForm F1G0= mulMod (F1, G0, buf);
3021        CanonicalForm F0G0= mulMod (F0, G0, MOD);
3022        CanonicalForm result= F0G0 + y*(F0G1 + F1G0);
3023        return result;
3024      }
3025    }
3026    else if (degF == 1 && degG == 0)
3027      return mulMod (div (F, y), G, buf)*y + mulMod (mod (F, y), G, buf);
3028    else if (degF == 0 && degG == 1)
3029      return mulMod (div (G, y), F, buf)*y + mulMod (mod (G, y), F, buf);
3030    else
3031      return mulMod (F, G, buf);
3032  }
3033  int m= (int) ceil (degree (M)/2.0);
3034  if (degF >= m || degG >= m)
3035  {
3036    CanonicalForm MLo= power (y, m);
3037    CanonicalForm MHi= power (y, degree (M) - m);
3038    CanonicalForm F0= mod (F, MLo);
3039    CanonicalForm F1= div (F, MLo);
3040    CanonicalForm G0= mod (G, MLo);
3041    CanonicalForm G1= div (G, MLo);
3042    CFList buf= MOD;
3043    buf.removeLast();
3044    buf.append (MHi);
3045    CanonicalForm F0G1= mulMod (F0, G1, buf);
3046    CanonicalForm F1G0= mulMod (F1, G0, buf);
3047    CanonicalForm F0G0= mulMod (F0, G0, MOD);
3048    return F0G0 + MLo*(F0G1 + F1G0);
3049  }
3050  else
3051  {
3052    m= (tmax(degF, degG)+1)/2;
3053    CanonicalForm yToM= power (y, m);
3054    CanonicalForm F0= mod (F, yToM);
3055    CanonicalForm F1= div (F, yToM);
3056    CanonicalForm G0= mod (G, yToM);
3057    CanonicalForm G1= div (G, yToM);
3058    CanonicalForm H00= mulMod (F0, G0, MOD);
3059    CanonicalForm H11= mulMod (F1, G1, MOD);
3060    CanonicalForm H01= mulMod (F0 + F1, G0 + G1, MOD);
3061    return H11*yToM*yToM + (H01 - H11 - H00)*yToM + H00;
3062  }
3063  DEBOUTLN (cerr, "fatal end in mulMod");
3064}
3065
3066CanonicalForm prodMod (const CFList& L, const CanonicalForm& M)
3067{
3068  if (L.isEmpty())
3069    return 1;
3070  int l= L.length();
3071  if (l == 1)
3072    return mod (L.getFirst(), M);
3073  else if (l == 2) {
3074    CanonicalForm result= mulMod2 (L.getFirst(), L.getLast(), M);
3075    return result;
3076  }
3077  else
3078  {
3079    l /= 2;
3080    CFList tmp1, tmp2;
3081    CFListIterator i= L;
3082    CanonicalForm buf1, buf2;
3083    for (int j= 1; j <= l; j++, i++)
3084      tmp1.append (i.getItem());
3085    tmp2= Difference (L, tmp1);
3086    buf1= prodMod (tmp1, M);
3087    buf2= prodMod (tmp2, M);
3088    CanonicalForm result= mulMod2 (buf1, buf2, M);
3089    return result;
3090  }
3091}
3092
3093CanonicalForm prodMod (const CFList& L, const CFList& M)
3094{
3095  if (L.isEmpty())
3096    return 1;
3097  else if (L.length() == 1)
3098    return L.getFirst();
3099  else if (L.length() == 2)
3100    return mulMod (L.getFirst(), L.getLast(), M);
3101  else
3102  {
3103    int l= L.length()/2;
3104    CFListIterator i= L;
3105    CFList tmp1, tmp2;
3106    CanonicalForm buf1, buf2;
3107    for (int j= 1; j <= l; j++, i++)
3108      tmp1.append (i.getItem());
3109    tmp2= Difference (L, tmp1);
3110    buf1= prodMod (tmp1, M);
3111    buf2= prodMod (tmp2, M);
3112    return mulMod (buf1, buf2, M);
3113  }
3114}
3115
3116// end multivariate polys
3117//***************************
3118// division
3119
3120CanonicalForm reverse (const CanonicalForm& F, int d)
3121{
3122  if (d == 0)
3123    return F;
3124  CanonicalForm A= F;
3125  Variable y= Variable (2);
3126  Variable x= Variable (1);
3127  if (degree (A, x) > 0)
3128  {
3129    A= swapvar (A, x, y);
3130    CanonicalForm result= 0;
3131    CFIterator i= A;
3132    while (d - i.exp() < 0)
3133      i++;
3134
3135    for (; i.hasTerms() && (d - i.exp() >= 0); i++)
3136      result += swapvar (i.coeff(),x,y)*power (x, d - i.exp());
3137    return result;
3138  }
3139  else
3140    return A*power (x, d);
3141}
3142
3143CanonicalForm
3144newtonInverse (const CanonicalForm& F, const int n, const CanonicalForm& M)
3145{
3146  int l= ilog2(n);
3147
3148  CanonicalForm g= mod (F, M)[0] [0];
3149
3150  ASSERT (!g.isZero(), "expected a unit");
3151
3152  Variable alpha;
3153
3154  if (!g.isOne())
3155    g = 1/g;
3156  Variable x= Variable (1);
3157  CanonicalForm result;
3158  int exp= 0;
3159  if (n & 1)
3160  {
3161    result= g;
3162    exp= 1;
3163  }
3164  CanonicalForm h;
3165
3166  for (int i= 1; i <= l; i++)
3167  {
3168    h= mulMod2 (g, mod (F, power (x, (1 << i))), M);
3169    h= mod (h, power (x, (1 << i)) - 1);
3170    h= div (h, power (x, (1 << (i - 1))));
3171    h= mod (h, M);
3172    g -= power (x, (1 << (i - 1)))*
3173         mod (mulMod2 (g, h, M), power (x, (1 << (i - 1))));
3174
3175    if (n & (1 << i))
3176    {
3177      if (exp)
3178      {
3179        h= mulMod2 (result, mod (F, power (x, exp + (1 << i))), M);
3180        h= mod (h, power (x, exp + (1 << i)) - 1);
3181        h= div (h, power (x, exp));
3182        h= mod (h, M);
3183        result -= power(x, exp)*mod (mulMod2 (g, h, M),
3184                                       power (x, (1 << i)));
3185        exp += (1 << i);
3186      }
3187      else
3188      {
3189        exp= (1 << i);
3190        result= g;
3191      }
3192    }
3193  }
3194
3195  return result;
3196}
3197
3198CanonicalForm
3199newtonDiv (const CanonicalForm& F, const CanonicalForm& G, const CanonicalForm&
3200           M)
3201{
3202  ASSERT (getCharacteristic() > 0, "positive characteristic expected");
3203
3204  CanonicalForm A= mod (F, M);
3205  CanonicalForm B= mod (G, M);
3206
3207  Variable x= Variable (1);
3208  int degA= degree (A, x);
3209  int degB= degree (B, x);
3210  int m= degA - degB;
3211  if (m < 0)
3212    return 0;
3213
3214  Variable v;
3215  CanonicalForm Q;
3216  if (degB < 1 || CFFactory::gettype() == GaloisFieldDomain)
3217  {
3218    CanonicalForm R;
3219    divrem2 (A, B, Q, R, M);
3220  }
3221  else
3222  {
3223    if (hasFirstAlgVar (A, v) || hasFirstAlgVar (B, v))
3224    {
3225      CanonicalForm R= reverse (A, degA);
3226      CanonicalForm revB= reverse (B, degB);
3227      revB= newtonInverse (revB, m + 1, M);
3228      Q= mulMod2 (R, revB, M);
3229      Q= mod (Q, power (x, m + 1));
3230      Q= reverse (Q, m);
3231    }
3232    else
3233    {
3234      Variable y= Variable (2);
3235#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
3236      nmod_poly_t FLINTmipo;
3237      fq_nmod_ctx_t fq_con;
3238
3239      nmod_poly_init (FLINTmipo, getCharacteristic());
3240      convertFacCF2nmod_poly_t (FLINTmipo, M);
3241
3242      fq_nmod_ctx_init_modulus (fq_con, FLINTmipo, "Z");
3243
3244
3245      fq_nmod_poly_t FLINTA, FLINTB;
3246      convertFacCF2Fq_nmod_poly_t (FLINTA, swapvar (A, x, y), fq_con);
3247      convertFacCF2Fq_nmod_poly_t (FLINTB, swapvar (B, x, y), fq_con);
3248
3249      fq_nmod_poly_divrem (FLINTA, FLINTB, FLINTA, FLINTB, fq_con);
3250
3251      Q= convertFq_nmod_poly_t2FacCF (FLINTA, x, y, fq_con);
3252
3253      fq_nmod_poly_clear (FLINTA, fq_con);
3254      fq_nmod_poly_clear (FLINTB, fq_con);
3255      nmod_poly_clear (FLINTmipo);
3256      fq_nmod_ctx_clear (fq_con);
3257#else
3258      bool zz_pEbak= zz_pE::initialized();
3259      zz_pEBak bak;
3260      if (zz_pEbak)
3261        bak.save();
3262      zz_pX mipo= convertFacCF2NTLzzpX (M);
3263      zz_pEX NTLA, NTLB;
3264      NTLA= convertFacCF2NTLzz_pEX (swapvar (A, x, y), mipo);
3265      NTLB= convertFacCF2NTLzz_pEX (swapvar (B, x, y), mipo);
3266      div (NTLA, NTLA, NTLB);
3267      Q= convertNTLzz_pEX2CF (NTLA, x, y);
3268      if (zz_pEbak)
3269        bak.restore();
3270#endif
3271    }
3272  }
3273
3274  return Q;
3275}
3276
3277void
3278newtonDivrem (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
3279              CanonicalForm& R, const CanonicalForm& M)
3280{
3281  CanonicalForm A= mod (F, M);
3282  CanonicalForm B= mod (G, M);
3283  Variable x= Variable (1);
3284  int degA= degree (A, x);
3285  int degB= degree (B, x);
3286  int m= degA - degB;
3287
3288  if (m < 0)
3289  {
3290    R= A;
3291    Q= 0;
3292    return;
3293  }
3294
3295  Variable v;
3296  if (degB <= 1 || CFFactory::gettype() == GaloisFieldDomain)
3297  {
3298     divrem2 (A, B, Q, R, M);
3299  }
3300  else
3301  {
3302    if (hasFirstAlgVar (A, v) || hasFirstAlgVar (B, v))
3303    {
3304      R= reverse (A, degA);
3305
3306      CanonicalForm revB= reverse (B, degB);
3307      revB= newtonInverse (revB, m + 1, M);
3308      Q= mulMod2 (R, revB, M);
3309
3310      Q= mod (Q, power (x, m + 1));
3311      Q= reverse (Q, m);
3312
3313      R= A - mulMod2 (Q, B, M);
3314    }
3315    else
3316    {
3317      Variable y= Variable (2);
3318#if (HAVE_FLINT &&  __FLINT_RELEASE >= 20400)
3319      nmod_poly_t FLINTmipo;
3320      fq_nmod_ctx_t fq_con;
3321
3322      nmod_poly_init (FLINTmipo, getCharacteristic());
3323      convertFacCF2nmod_poly_t (FLINTmipo, M);
3324
3325      fq_nmod_ctx_init_modulus (fq_con, FLINTmipo, "Z");
3326
3327      fq_nmod_poly_t FLINTA, FLINTB;
3328      convertFacCF2Fq_nmod_poly_t (FLINTA, swapvar (A, x, y), fq_con);
3329      convertFacCF2Fq_nmod_poly_t (FLINTB, swapvar (B, x, y), fq_con);
3330
3331      fq_nmod_poly_divrem (FLINTA, FLINTB, FLINTA, FLINTB, fq_con);
3332
3333      Q= convertFq_nmod_poly_t2FacCF (FLINTA, x, y, fq_con);
3334      R= convertFq_nmod_poly_t2FacCF (FLINTB, x, y, fq_con);
3335
3336      fq_nmod_poly_clear (FLINTA, fq_con);
3337      fq_nmod_poly_clear (FLINTB, fq_con);
3338      nmod_poly_clear (FLINTmipo);
3339      fq_nmod_ctx_clear (fq_con);
3340#else
3341      zz_pX mipo= convertFacCF2NTLzzpX (M);
3342      zz_pEX NTLA, NTLB;
3343      NTLA= convertFacCF2NTLzz_pEX (swapvar (A, x, y), mipo);
3344      NTLB= convertFacCF2NTLzz_pEX (swapvar (B, x, y), mipo);
3345      zz_pEX NTLQ, NTLR;
3346      DivRem (NTLQ, NTLR, NTLA, NTLB);
3347      Q= convertNTLzz_pEX2CF (NTLQ, x, y);
3348      R= convertNTLzz_pEX2CF (NTLR, x, y);
3349#endif
3350    }
3351  }
3352}
3353
3354static inline
3355CFList split (const CanonicalForm& F, const int m, const Variable& x)
3356{
3357  CanonicalForm A= F;
3358  CanonicalForm buf= 0;
3359  bool swap= false;
3360  if (degree (A, x) <= 0)
3361    return CFList(A);
3362  else if (x.level() != A.level())
3363  {
3364    swap= true;
3365    A= swapvar (A, x, A.mvar());
3366  }
3367
3368  int j= (int) floor ((double) degree (A)/ m);
3369  CFList result;
3370  CFIterator i= A;
3371  for (; j >= 0; j--)
3372  {
3373    while (i.hasTerms() && i.exp() - j*m >= 0)
3374    {
3375      if (swap)
3376        buf += i.coeff()*power (A.mvar(), i.exp() - j*m);
3377      else
3378        buf += i.coeff()*power (x, i.exp() - j*m);
3379      i++;
3380    }
3381    if (swap)
3382      result.append (swapvar (buf, x, F.mvar()));
3383    else
3384      result.append (buf);
3385    buf= 0;
3386  }
3387  return result;
3388}
3389
3390static inline
3391void divrem32 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
3392               CanonicalForm& R, const CFList& M);
3393
3394static inline
3395void divrem21 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
3396               CanonicalForm& R, const CFList& M)
3397{
3398  CanonicalForm A= mod (F, M);
3399  CanonicalForm B= mod (G, M);
3400  Variable x= Variable (1);
3401  int degB= degree (B, x);
3402  int degA= degree (A, x);
3403  if (degA < degB)
3404  {
3405    Q= 0;
3406    R= A;
3407    return;
3408  }
3409  if (degB < 1)
3410  {
3411    divrem (A, B, Q, R);
3412    Q= mod (Q, M);
3413    R= mod (R, M);
3414    return;
3415  }
3416  int m= (int) ceil ((double) (degB + 1)/2.0) + 1;
3417  ASSERT (4*m >= degA, "expected degree (F, 1) < 2*degree (G, 1)");
3418  CFList splitA= split (A, m, x);
3419  if (splitA.length() == 3)
3420    splitA.insert (0);
3421  if (splitA.length() == 2)
3422  {
3423    splitA.insert (0);
3424    splitA.insert (0);
3425  }
3426  if (splitA.length() == 1)
3427  {
3428    splitA.insert (0);
3429    splitA.insert (0);
3430    splitA.insert (0);
3431  }
3432
3433  CanonicalForm xToM= power (x, m);
3434
3435  CFListIterator i= splitA;
3436  CanonicalForm H= i.getItem();
3437  i++;
3438  H *= xToM;
3439  H += i.getItem();
3440  i++;
3441  H *= xToM;
3442  H += i.getItem();
3443  i++;
3444
3445  divrem32 (H, B, Q, R, M);
3446
3447  CFList splitR= split (R, m, x);
3448  if (splitR.length() == 1)
3449    splitR.insert (0);
3450
3451  H= splitR.getFirst();
3452  H *= xToM;
3453  H += splitR.getLast();
3454  H *= xToM;
3455  H += i.getItem();
3456
3457  CanonicalForm bufQ;
3458  divrem32 (H, B, bufQ, R, M);
3459
3460  Q *= xToM;
3461  Q += bufQ;
3462  return;
3463}
3464
3465static inline
3466void divrem32 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
3467               CanonicalForm& R, const CFList& M)
3468{
3469  CanonicalForm A= mod (F, M);
3470  CanonicalForm B= mod (G, M);
3471  Variable x= Variable (1);
3472  int degB= degree (B, x);
3473  int degA= degree (A, x);
3474  if (degA < degB)
3475  {
3476    Q= 0;
3477    R= A;
3478    return;
3479  }
3480  if (degB < 1)
3481  {
3482    divrem (A, B, Q, R);
3483    Q= mod (Q, M);
3484    R= mod (R, M);
3485    return;
3486  }
3487  int m= (int) ceil ((double) (degB + 1)/ 2.0);
3488  ASSERT (3*m > degA, "expected degree (F, 1) < 3*degree (G, 1)");
3489  CFList splitA= split (A, m, x);
3490  CFList splitB= split (B, m, x);
3491
3492  if (splitA.length() == 2)
3493  {
3494    splitA.insert (0);
3495  }
3496  if (splitA.length() == 1)
3497  {
3498    splitA.insert (0);
3499    splitA.insert (0);
3500  }
3501  CanonicalForm xToM= power (x, m);
3502
3503  CanonicalForm H;
3504  CFListIterator i= splitA;
3505  i++;
3506
3507  if (degree (splitA.getFirst(), x) < degree (splitB.getFirst(), x))
3508  {
3509    H= splitA.getFirst()*xToM + i.getItem();
3510    divrem21 (H, splitB.getFirst(), Q, R, M);
3511  }
3512  else
3513  {
3514    R= splitA.getFirst()*xToM + i.getItem() + splitB.getFirst() -
3515       splitB.getFirst()*xToM;
3516    Q= xToM - 1;
3517  }
3518
3519  H= mulMod (Q, splitB.getLast(), M);
3520
3521  R= R*xToM + splitA.getLast() - H;
3522
3523  while (degree (R, x) >= degB)
3524  {
3525    xToM= power (x, degree (R, x) - degB);
3526    Q += LC (R, x)*xToM;
3527    R -= mulMod (LC (R, x), B, M)*xToM;
3528    Q= mod (Q, M);
3529    R= mod (R, M);
3530  }
3531
3532  return;
3533}
3534
3535void divrem2 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
3536              CanonicalForm& R, const CanonicalForm& M)
3537{
3538  CanonicalForm A= mod (F, M);
3539  CanonicalForm B= mod (G, M);
3540
3541  if (B.inCoeffDomain())
3542  {
3543    divrem (A, B, Q, R);
3544    return;
3545  }
3546  if (A.inCoeffDomain() && !B.inCoeffDomain())
3547  {
3548    Q= 0;
3549    R= A;
3550    return;
3551  }
3552
3553  if (B.level() < A.level())
3554  {
3555    divrem (A, B, Q, R);
3556    return;
3557  }
3558  if (A.level() > B.level())
3559  {
3560    R= A;
3561    Q= 0;
3562    return;
3563  }
3564  if (B.level() == 1 && B.isUnivariate())
3565  {
3566    divrem (A, B, Q, R);
3567    return;
3568  }
3569
3570  Variable x= Variable (1);
3571  int degB= degree (B, x);
3572  if (degB > degree (A, x))
3573  {
3574    Q= 0;
3575    R= A;
3576    return;
3577  }
3578
3579  CFList splitA= split (A, degB, x);
3580
3581  CanonicalForm xToDegB= power (x, degB);
3582  CanonicalForm H, bufQ;
3583  Q= 0;
3584  CFListIterator i= splitA;
3585  H= i.getItem()*xToDegB;
3586  i++;
3587  H += i.getItem();
3588  CFList buf;
3589  while (i.hasItem())
3590  {
3591    buf= CFList (M);
3592    divrem21 (H, B, bufQ, R, buf);
3593    i++;
3594    if (i.hasItem())
3595      H= R*xToDegB + i.getItem();
3596    Q *= xToDegB;
3597    Q += bufQ;
3598  }
3599  return;
3600}
3601
3602void divrem (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
3603             CanonicalForm& R, const CFList& MOD)
3604{
3605  CanonicalForm A= mod (F, MOD);
3606  CanonicalForm B= mod (G, MOD);
3607  Variable x= Variable (1);
3608  int degB= degree (B, x);
3609  if (degB > degree (A, x))
3610  {
3611    Q= 0;
3612    R= A;
3613    return;
3614  }
3615
3616  if (degB <= 0)
3617  {
3618    divrem (A, B, Q, R);
3619    Q= mod (Q, MOD);
3620    R= mod (R, MOD);
3621    return;
3622  }
3623  CFList splitA= split (A, degB, x);
3624
3625  CanonicalForm xToDegB= power (x, degB);
3626  CanonicalForm H, bufQ;
3627  Q= 0;
3628  CFListIterator i= splitA;
3629  H= i.getItem()*xToDegB;
3630  i++;
3631  H += i.getItem();
3632  while (i.hasItem())
3633  {
3634    divrem21 (H, B, bufQ, R, MOD);
3635    i++;
3636    if (i.hasItem())
3637      H= R*xToDegB + i.getItem();
3638    Q *= xToDegB;
3639    Q += bufQ;
3640  }
3641  return;
3642}
3643
3644bool
3645uniFdivides (const CanonicalForm& A, const CanonicalForm& B)
3646{
3647  if (B.isZero())
3648    return true;
3649  if (A.isZero())
3650    return false;
3651  if (CFFactory::gettype() == GaloisFieldDomain)
3652    return fdivides (A, B);
3653  int p= getCharacteristic();
3654  if (A.inCoeffDomain() || B.inCoeffDomain())
3655  {
3656    if (A.inCoeffDomain())
3657      return true;
3658    else
3659      return false;
3660  }
3661  if (p > 0)
3662  {
3663#if (!defined(HAVE_FLINT) ||  __FLINT_RELEASE < 20400)
3664    if (fac_NTL_char != p)
3665    {
3666      fac_NTL_char= p;
3667      zz_p::init (p);
3668    }
3669#endif
3670    Variable alpha;
3671    if (hasFirstAlgVar (A, alpha) || hasFirstAlgVar (B, alpha))
3672    {
3673#if (HAVE_FLINT && __FLINT_RELEASE >= 20400)
3674      nmod_poly_t FLINTmipo;
3675      fq_nmod_ctx_t fq_con;
3676
3677      nmod_poly_init (FLINTmipo, getCharacteristic());
3678      convertFacCF2nmod_poly_t (FLINTmipo, getMipo (alpha));
3679
3680      fq_nmod_ctx_init_modulus (fq_con, FLINTmipo, "Z");
3681
3682      fq_nmod_poly_t FLINTA, FLINTB;
3683      convertFacCF2Fq_nmod_poly_t (FLINTA, A, fq_con);
3684      convertFacCF2Fq_nmod_poly_t (FLINTB, B, fq_con);
3685      int result= fq_nmod_poly_divides (FLINTA, FLINTB, FLINTA, fq_con);
3686      fq_nmod_poly_clear (FLINTA, fq_con);
3687      fq_nmod_poly_clear (FLINTB, fq_con);
3688      nmod_poly_clear (FLINTmipo);
3689      fq_nmod_ctx_clear (fq_con);
3690      return result;
3691#else
3692      zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
3693      zz_pE::init (NTLMipo);
3694      zz_pEX NTLA= convertFacCF2NTLzz_pEX (A, NTLMipo);
3695      zz_pEX NTLB= convertFacCF2NTLzz_pEX (B, NTLMipo);
3696      return divide (NTLB, NTLA);
3697#endif
3698    }
3699#ifdef HAVE_FLINT
3700    nmod_poly_t FLINTA, FLINTB;
3701    convertFacCF2nmod_poly_t (FLINTA, A);
3702    convertFacCF2nmod_poly_t (FLINTB, B);
3703    nmod_poly_divrem (FLINTB, FLINTA, FLINTB, FLINTA);
3704    bool result= nmod_poly_is_zero (FLINTA);
3705    nmod_poly_clear (FLINTA);
3706    nmod_poly_clear (FLINTB);
3707    return result;
3708#else
3709    zz_pX NTLA= convertFacCF2NTLzzpX (A);
3710    zz_pX NTLB= convertFacCF2NTLzzpX (B);
3711    return divide (NTLB, NTLA);
3712#endif
3713  }
3714#ifdef HAVE_FLINT
3715  Variable alpha;
3716  bool isRat= isOn (SW_RATIONAL);
3717  if (!isRat)
3718    On (SW_RATIONAL);
3719  if (!hasFirstAlgVar (A, alpha) && !hasFirstAlgVar (B, alpha))
3720  {
3721    fmpq_poly_t FLINTA,FLINTB;
3722    convertFacCF2Fmpq_poly_t (FLINTA, A);
3723    convertFacCF2Fmpq_poly_t (FLINTB, B);
3724    fmpq_poly_rem (FLINTA, FLINTB, FLINTA);
3725    bool result= fmpq_poly_is_zero (FLINTA);
3726    fmpq_poly_clear (FLINTA);
3727    fmpq_poly_clear (FLINTB);
3728    if (!isRat)
3729      Off (SW_RATIONAL);
3730    return result;
3731  }
3732  CanonicalForm Q, R;
3733  newtonDivrem (B, A, Q, R);
3734  if (!isRat)
3735    Off (SW_RATIONAL);
3736  return R.isZero();
3737#else
3738  bool isRat= isOn (SW_RATIONAL);
3739  if (!isRat)
3740    On (SW_RATIONAL);
3741  bool result= fdivides (A, B);
3742  if (!isRat)
3743    Off (SW_RATIONAL);
3744  return result; //maybe NTL?
3745#endif
3746}
3747
3748// end division
3749
3750#else
3751CanonicalForm
3752mulNTL (const CanonicalForm& F, const CanonicalForm& G, const modpk& b)
3753{ return F*G; }
3754#endif
Note: See TracBrowser for help on using the repository browser.