source: git/factory/facMul.cc @ 329dd3

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