source: git/factory/facMul.cc @ baa2c3a

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