source: git/factory/facMul.cc @ 347a89

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