source: git/factory/facHensel.cc @ 5df7d0

fieker-DuValspielwiese
Last change on this file since 5df7d0 was 64e7cb, checked in by Martin Lee <martinlee84@…>, 13 years ago
prepare Hensel lifting for char= 0 case git-svn-id: file:///usr/local/Singular/svn/trunk@14296 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 82.0 KB
Line 
1/*****************************************************************************\
2 * Computer Algebra System SINGULAR
3\*****************************************************************************/
4/** @file facHensel.cc
5 *
6 * This file implements functions to lift factors via Hensel lifting and
7 * functions for modular multiplication and division with remainder.
8 *
9 * ABSTRACT: Hensel lifting is described in "Efficient Multivariate
10 * Factorization over Finite Fields" by L. Bernardin & M. Monagon. Division with
11 * remainder is described in "Fast Recursive Division" by C. Burnikel and
12 * J. Ziegler. Karatsuba multiplication is described in "Modern Computer
13 * Algebra" by J. von zur Gathen and J. Gerhard.
14 *
15 * @author Martin Lee
16 *
17 * @internal @version \$Id$
18 *
19 **/
20/*****************************************************************************/
21
22#include "assert.h"
23#include "debug.h"
24#include "timing.h"
25
26#include "facHensel.h"
27#include "cf_util.h"
28#include "fac_util.h"
29#include "cf_algorithm.h"
30
31#ifdef HAVE_NTL
32#include <NTL/lzz_pEX.h>
33#include "NTLconvert.h"
34
35CanonicalForm
36mulNTL (const CanonicalForm& F, const CanonicalForm& G)
37{
38  if (F.inCoeffDomain() || G.inCoeffDomain() || getCharacteristic() == 0)
39    return F*G;
40  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
41  ASSERT (F.level() == G.level(), "expected polys of same level");
42  if (CFFactory::gettype() == GaloisFieldDomain)
43    return F*G;
44  zz_p::init (getCharacteristic());
45  Variable alpha;
46  CanonicalForm result;
47  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
48  {
49    zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
50    zz_pE::init (NTLMipo);
51    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
52    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
53    mul (NTLF, NTLF, NTLG);
54    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
55  }
56  else
57  {
58    zz_pX NTLF= convertFacCF2NTLzzpX (F);
59    zz_pX NTLG= convertFacCF2NTLzzpX (G);
60    mul (NTLF, NTLF, NTLG);
61    result= convertNTLzzpX2CF(NTLF, F.mvar());
62  }
63  return result;
64}
65
66CanonicalForm
67modNTL (const CanonicalForm& F, const CanonicalForm& G)
68{
69  if (F.inCoeffDomain() && G.isUnivariate())
70    return F;
71  else if (F.inCoeffDomain() && G.inCoeffDomain())
72    return mod (F, G);
73  else if (F.isUnivariate() && G.inCoeffDomain())
74    return mod (F,G);
75
76  if (getCharacteristic() == 0)
77    return mod (F, G);
78
79  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
80  ASSERT (F.level() == G.level(), "expected polys of same level");
81  if (CFFactory::gettype() == GaloisFieldDomain)
82    return mod (F, G);
83  zz_p::init (getCharacteristic());
84  Variable alpha;
85  CanonicalForm result;
86  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
87  {
88    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
89    zz_pE::init (NTLMipo);
90    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
91    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
92    rem (NTLF, NTLF, NTLG);
93    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
94  }
95  else
96  {
97    zz_pX NTLF= convertFacCF2NTLzzpX (F);
98    zz_pX NTLG= convertFacCF2NTLzzpX (G);
99    rem (NTLF, NTLF, NTLG);
100    result= convertNTLzzpX2CF(NTLF, F.mvar());
101  }
102  return result;
103}
104
105CanonicalForm
106divNTL (const CanonicalForm& F, const CanonicalForm& G)
107{
108  if (F.inCoeffDomain() && G.isUnivariate())
109    return F;
110  else if (F.inCoeffDomain() && G.inCoeffDomain())
111    return div (F, G);
112  else if (F.isUnivariate() && G.inCoeffDomain())
113    return div (F,G);
114
115  if (getCharacteristic() == 0)
116    return div (F, G);
117
118  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
119  ASSERT (F.level() == G.level(), "expected polys of same level");
120  if (CFFactory::gettype() == GaloisFieldDomain)
121    return div (F, G);
122  zz_p::init (getCharacteristic());
123  Variable alpha;
124  CanonicalForm result;
125  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
126  {
127    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
128    zz_pE::init (NTLMipo);
129    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
130    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
131    div (NTLF, NTLF, NTLG);
132    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
133  }
134  else
135  {
136    zz_pX NTLF= convertFacCF2NTLzzpX (F);
137    zz_pX NTLG= convertFacCF2NTLzzpX (G);
138    div (NTLF, NTLF, NTLG);
139    result= convertNTLzzpX2CF(NTLF, F.mvar());
140  }
141  return result;
142}
143
144/*
145void
146divremNTL (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
147           CanonicalForm& R)
148{
149  if (F.inCoeffDomain() && G.isUnivariate())
150  {
151    R= F;
152    Q= 0;
153  }
154  else if (F.inCoeffDomain() && G.inCoeffDomain())
155  {
156    divrem (F, G, Q, R);
157    return;
158  }
159  else if (F.isUnivariate() && G.inCoeffDomain())
160  {
161    divrem (F, G, Q, R);
162    return;
163  }
164
165  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
166  ASSERT (F.level() == G.level(), "expected polys of same level");
167  if (CFFactory::gettype() == GaloisFieldDomain)
168  {
169    divrem (F, G, Q, R);
170    return;
171  }
172  zz_p::init (getCharacteristic());
173  Variable alpha;
174  CanonicalForm result;
175  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
176  {
177    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
178    zz_pE::init (NTLMipo);
179    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
180    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
181    zz_pEX NTLQ;
182    zz_pEX NTLR;
183    DivRem (NTLQ, NTLR, NTLF, NTLG);
184    Q= convertNTLzz_pEX2CF(NTLQ, F.mvar(), alpha);
185    R= convertNTLzz_pEX2CF(NTLR, F.mvar(), alpha);
186    return;
187  }
188  else
189  {
190    zz_pX NTLF= convertFacCF2NTLzzpX (F);
191    zz_pX NTLG= convertFacCF2NTLzzpX (G);
192    zz_pX NTLQ;
193    zz_pX NTLR;
194    DivRem (NTLQ, NTLR, NTLF, NTLG);
195    Q= convertNTLzzpX2CF(NTLQ, F.mvar());
196    R= convertNTLzzpX2CF(NTLR, F.mvar());
197    return;
198  }
199}*/
200
201CanonicalForm mod (const CanonicalForm& F, const CFList& M)
202{
203  CanonicalForm A= F;
204  for (CFListIterator i= M; i.hasItem(); i++)
205    A= mod (A, i.getItem());
206  return A;
207}
208
209zz_pX kronSubFp (const CanonicalForm& A, int d)
210{
211  int degAy= degree (A);
212  zz_pX result;
213  result.rep.SetLength (d*(degAy + 1));
214
215  zz_p *resultp;
216  resultp= result.rep.elts();
217  zz_pX buf;
218  zz_p *bufp;
219
220  for (CFIterator i= A; i.hasTerms(); i++)
221  {
222    if (i.coeff().inCoeffDomain())
223      buf= convertFacCF2NTLzzpX (i.coeff());
224    else
225      buf= convertFacCF2NTLzzpX (i.coeff());
226
227    int k= i.exp()*d;
228    bufp= buf.rep.elts();
229    int bufRepLength= (int) buf.rep.length();
230    for (int j= 0; j < bufRepLength; j++)
231      resultp [j + k]= bufp [j];
232  }
233  result.normalize();
234
235  return result;
236}
237
238zz_pEX kronSub (const CanonicalForm& A, int d, const Variable& alpha)
239{
240  int degAy= degree (A);
241  zz_pEX result;
242  result.rep.SetLength (d*(degAy + 1));
243
244  Variable v;
245  zz_pE *resultp;
246  resultp= result.rep.elts();
247  zz_pEX buf1;
248  zz_pE *buf1p;
249  zz_pX buf2;
250  zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
251
252  for (CFIterator i= A; i.hasTerms(); i++)
253  {
254    if (i.coeff().inCoeffDomain())
255    {
256      buf2= convertFacCF2NTLzzpX (i.coeff());
257      buf1= to_zz_pEX (to_zz_pE (buf2));
258    }
259    else
260      buf1= convertFacCF2NTLzz_pEX (i.coeff(), NTLMipo);
261
262    int k= i.exp()*d;
263    buf1p= buf1.rep.elts();
264    int buf1RepLength= (int) buf1.rep.length();
265    for (int j= 0; j < buf1RepLength; j++)
266      resultp [j + k]= buf1p [j];
267  }
268  result.normalize();
269
270  return result;
271}
272
273void
274kronSubRecipro (zz_pEX& subA1, zz_pEX& subA2,const CanonicalForm& A, int d,
275                const Variable& alpha)
276{
277  int degAy= degree (A);
278  subA1.rep.SetLength ((long) d*(degAy + 1));
279  subA2.rep.SetLength ((long) d*(degAy + 1));
280
281  Variable v;
282  zz_pE *subA1p;
283  zz_pE *subA2p;
284  subA1p= subA1.rep.elts();
285  subA2p= subA2.rep.elts();
286  zz_pEX buf;
287  zz_pE *bufp;
288  zz_pX buf2;
289  zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
290
291  for (CFIterator i= A; i.hasTerms(); i++)
292  {
293    if (i.coeff().inCoeffDomain())
294    {
295      buf2= convertFacCF2NTLzzpX (i.coeff());
296      buf= to_zz_pEX (to_zz_pE (buf2));
297    }
298    else
299      buf= convertFacCF2NTLzz_pEX (i.coeff(), NTLMipo);
300
301    int k= i.exp()*d;
302    int kk= (degAy - i.exp())*d;
303    bufp= buf.rep.elts();
304    int bufRepLength= (int) buf.rep.length();
305    for (int j= 0; j < bufRepLength; j++)
306    {
307      subA1p [j + k]= bufp [j];
308      subA2p [j + kk]= bufp [j];
309    }
310  }
311  subA1.normalize();
312  subA2.normalize();
313}
314
315void
316kronSubRecipro (zz_pX& subA1, zz_pX& subA2,const CanonicalForm& A, int d)
317{
318  int degAy= degree (A);
319  subA1.rep.SetLength ((long) d*(degAy + 1));
320  subA2.rep.SetLength ((long) d*(degAy + 1));
321
322  Variable v;
323  zz_p *subA1p;
324  zz_p *subA2p;
325  subA1p= subA1.rep.elts();
326  subA2p= subA2.rep.elts();
327  zz_pX buf;
328  zz_p *bufp;
329
330  for (CFIterator i= A; i.hasTerms(); i++)
331  {
332    buf= convertFacCF2NTLzzpX (i.coeff());
333
334    int k= i.exp()*d;
335    int kk= (degAy - i.exp())*d;
336    bufp= buf.rep.elts();
337    int bufRepLength= (int) buf.rep.length();
338    for (int j= 0; j < bufRepLength; j++)
339    {
340      subA1p [j + k]= bufp [j];
341      subA2p [j + kk]= bufp [j];
342    }
343  }
344  subA1.normalize();
345  subA2.normalize();
346}
347
348CanonicalForm
349reverseSubst (const zz_pEX& F, const zz_pEX& G, int d, int k,
350              const Variable& alpha)
351{
352  Variable y= Variable (2);
353  Variable x= Variable (1);
354
355  zz_pEX f= F;
356  zz_pEX g= G;
357  int degf= deg(f);
358  int degg= deg(g);
359
360  zz_pEX buf1;
361  zz_pEX buf2;
362  zz_pEX buf3;
363
364  zz_pE *buf1p;
365  zz_pE *buf2p;
366  zz_pE *buf3p;
367  if (f.rep.length() < (long) d*(k+1)) //zero padding
368    f.rep.SetLength ((long)d*(k+1));
369
370  zz_pE *gp= g.rep.elts();
371  zz_pE *fp= f.rep.elts();
372  CanonicalForm result= 0;
373  int i= 0;
374  int lf= 0;
375  int lg= d*k;
376  int degfSubLf= degf;
377  int deggSubLg= degg-lg;
378  int repLengthBuf2;
379  int repLengthBuf1;
380  zz_pE zzpEZero= zz_pE();
381
382  while (degf >= lf || lg >= 0)
383  {
384    if (degfSubLf >= d)
385      repLengthBuf1= d;
386    else if (degfSubLf < 0)
387      repLengthBuf1= 0;
388    else
389      repLengthBuf1= degfSubLf + 1;
390    buf1.rep.SetLength((long) repLengthBuf1);
391
392    buf1p= buf1.rep.elts();
393    for (int ind= 0; ind < repLengthBuf1; ind++)
394      buf1p [ind]= fp [ind + lf];
395    buf1.normalize();
396
397    repLengthBuf1= buf1.rep.length();
398
399    if (deggSubLg >= d - 1)
400      repLengthBuf2= d - 1;
401    else if (deggSubLg < 0)
402      repLengthBuf2= 0;
403    else
404      repLengthBuf2= deggSubLg + 1;
405
406    buf2.rep.SetLength ((long) repLengthBuf2);
407    buf2p= buf2.rep.elts();
408    for (int ind= 0; ind < repLengthBuf2; ind++)
409    {
410      buf2p [ind]= gp [ind + lg];
411    }
412    buf2.normalize();
413
414    repLengthBuf2= buf2.rep.length();
415
416    buf3.rep.SetLength((long) repLengthBuf2 + d);
417    buf3p= buf3.rep.elts();
418    buf2p= buf2.rep.elts();
419    buf1p= buf1.rep.elts();
420    for (int ind= 0; ind < repLengthBuf1; ind++)
421      buf3p [ind]= buf1p [ind];
422    for (int ind= repLengthBuf1; ind < d; ind++)
423      buf3p [ind]= zzpEZero;
424    for (int ind= 0; ind < repLengthBuf2; ind++)
425      buf3p [ind + d]= buf2p [ind];
426    buf3.normalize();
427
428    result += convertNTLzz_pEX2CF (buf3, x, alpha)*power (y, i);
429    i++;
430
431
432    lf= i*d;
433    degfSubLf= degf - lf;
434
435    lg= d*(k-i);
436    deggSubLg= degg - lg;
437
438    buf1p= buf1.rep.elts();
439
440    if (lg >= 0 && deggSubLg > 0)
441    {
442      if (repLengthBuf2 > degfSubLf + 1)
443        degfSubLf= repLengthBuf2 - 1;
444      int tmp= tmin (repLengthBuf1, deggSubLg);
445      for (int ind= 0; ind < tmp; ind++)
446        gp [ind + lg] -= buf1p [ind];
447    }
448
449    if (lg < 0)
450      break;
451
452    buf2p= buf2.rep.elts();
453    if (degfSubLf >= 0)
454    {
455      for (int ind= 0; ind < repLengthBuf2; ind++)
456        fp [ind + lf] -= buf2p [ind];
457    }
458  }
459
460  return result;
461}
462
463CanonicalForm
464reverseSubst (const zz_pX& F, const zz_pX& G, int d, int k)
465{
466  Variable y= Variable (2);
467  Variable x= Variable (1);
468
469  zz_pX f= F;
470  zz_pX g= G;
471  int degf= deg(f);
472  int degg= deg(g);
473
474  zz_pX buf1;
475  zz_pX buf2;
476  zz_pX buf3;
477
478  zz_p *buf1p;
479  zz_p *buf2p;
480  zz_p *buf3p;
481
482  if (f.rep.length() < (long) d*(k+1)) //zero padding
483    f.rep.SetLength ((long)d*(k+1));
484
485  zz_p *gp= g.rep.elts();
486  zz_p *fp= f.rep.elts();
487  CanonicalForm result= 0;
488  int i= 0;
489  int lf= 0;
490  int lg= d*k;
491  int degfSubLf= degf;
492  int deggSubLg= degg-lg;
493  int repLengthBuf2;
494  int repLengthBuf1;
495  zz_p zzpZero= zz_p();
496  while (degf >= lf || lg >= 0)
497  {
498    if (degfSubLf >= d)
499      repLengthBuf1= d;
500    else if (degfSubLf < 0)
501      repLengthBuf1= 0;
502    else
503      repLengthBuf1= degfSubLf + 1;
504    buf1.rep.SetLength((long) repLengthBuf1);
505
506    buf1p= buf1.rep.elts();
507    for (int ind= 0; ind < repLengthBuf1; ind++)
508      buf1p [ind]= fp [ind + lf];
509    buf1.normalize();
510
511    repLengthBuf1= buf1.rep.length();
512
513    if (deggSubLg >= d - 1)
514      repLengthBuf2= d - 1;
515    else if (deggSubLg < 0)
516      repLengthBuf2= 0;
517    else
518      repLengthBuf2= deggSubLg + 1;
519
520    buf2.rep.SetLength ((long) repLengthBuf2);
521    buf2p= buf2.rep.elts();
522    for (int ind= 0; ind < repLengthBuf2; ind++)
523      buf2p [ind]= gp [ind + lg];
524
525    buf2.normalize();
526
527    repLengthBuf2= buf2.rep.length();
528
529
530    buf3.rep.SetLength((long) repLengthBuf2 + d);
531    buf3p= buf3.rep.elts();
532    buf2p= buf2.rep.elts();
533    buf1p= buf1.rep.elts();
534    for (int ind= 0; ind < repLengthBuf1; ind++)
535      buf3p [ind]= buf1p [ind];
536    for (int ind= repLengthBuf1; ind < d; ind++)
537      buf3p [ind]= zzpZero;
538    for (int ind= 0; ind < repLengthBuf2; ind++)
539      buf3p [ind + d]= buf2p [ind];
540    buf3.normalize();
541
542    result += convertNTLzzpX2CF (buf3, x)*power (y, i);
543    i++;
544
545
546    lf= i*d;
547    degfSubLf= degf - lf;
548
549    lg= d*(k-i);
550    deggSubLg= degg - lg;
551
552    buf1p= buf1.rep.elts();
553
554    if (lg >= 0 && deggSubLg > 0)
555    {
556      if (repLengthBuf2 > degfSubLf + 1)
557        degfSubLf= repLengthBuf2 - 1;
558      int tmp= tmin (repLengthBuf1, deggSubLg);
559      for (int ind= 0; ind < tmp; ind++)
560        gp [ind + lg] -= buf1p [ind];
561    }
562    if (lg < 0)
563      break;
564
565    buf2p= buf2.rep.elts();
566    if (degfSubLf >= 0)
567    {
568      for (int ind= 0; ind < repLengthBuf2; ind++)
569        fp [ind + lf] -= buf2p [ind];
570    }
571  }
572
573  return result;
574}
575
576CanonicalForm reverseSubst (const zz_pEX& F, int d, const Variable& alpha)
577{
578  Variable y= Variable (2);
579  Variable x= Variable (1);
580
581  zz_pEX f= F;
582  zz_pE *fp= f.rep.elts();
583
584  zz_pEX buf;
585  zz_pE *bufp;
586  CanonicalForm result= 0;
587  int i= 0;
588  int degf= deg(f);
589  int k= 0;
590  int degfSubK;
591  int repLength;
592  while (degf >= k)
593  {
594    degfSubK= degf - k;
595    if (degfSubK >= d)
596      repLength= d;
597    else
598      repLength= degfSubK + 1;
599
600    buf.rep.SetLength ((long) repLength);
601    bufp= buf.rep.elts();
602    for (int j= 0; j < repLength; j++)
603      bufp [j]= fp [j + k];
604    buf.normalize();
605
606    result += convertNTLzz_pEX2CF (buf, x, alpha)*power (y, i);
607    i++;
608    k= d*i;
609  }
610
611  return result;
612}
613
614CanonicalForm reverseSubstFp (const zz_pX& F, int d)
615{
616  Variable y= Variable (2);
617  Variable x= Variable (1);
618
619  zz_pX f= F;
620  zz_p *fp= f.rep.elts();
621
622  zz_pX buf;
623  zz_p *bufp;
624  CanonicalForm result= 0;
625  int i= 0;
626  int degf= deg(f);
627  int k= 0;
628  int degfSubK;
629  int repLength;
630  while (degf >= k)
631  {
632    degfSubK= degf - k;
633    if (degfSubK >= d)
634      repLength= d;
635    else
636      repLength= degfSubK + 1;
637
638    buf.rep.SetLength ((long) repLength);
639    bufp= buf.rep.elts();
640    for (int j= 0; j < repLength; j++)
641      bufp [j]= fp [j + k];
642    buf.normalize();
643
644    result += convertNTLzzpX2CF (buf, x)*power (y, i);
645    i++;
646    k= d*i;
647  }
648
649  return result;
650}
651
652// assumes input to be reduced mod M and to be an element of Fq not Fp
653CanonicalForm
654mulMod2NTLFpReci (const CanonicalForm& F, const CanonicalForm& G, const
655                  CanonicalForm& M)
656{
657  int d1= tmax (degree (F, 1), degree (G, 1)) + 1;
658  int d2= tmax (degree (F, 2), degree (G, 2));
659
660  zz_pX F1, F2;
661  kronSubRecipro (F1, F2, F, d1);
662  zz_pX G1, G2;
663  kronSubRecipro (G1, G2, G, d1);
664
665  int k= d1*degree (M);
666  MulTrunc (F1, F1, G1, (long) k);
667
668  mul (F2, F2, G2);
669  F2 >>= k;
670
671  return reverseSubst (F1, F2, d1, d2);
672}
673
674//Kronecker substitution
675CanonicalForm
676mulMod2NTLFp (const CanonicalForm& F, const CanonicalForm& G, const
677              CanonicalForm& M)
678{
679  CanonicalForm A= F;
680  CanonicalForm B= G;
681
682  int degAx= degree (A, 1);
683  int degAy= degree (A, 2);
684  int degBx= degree (B, 1);
685  int degBy= degree (B, 2);
686  int d1= degAx + 1 + degBx;
687  int d2= tmax (degree (A, 2), degree (B, 2));
688
689  if (d1 > 128 && d2 > 160 && (degAy == degBy))
690    return mulMod2NTLFpReci (A, B, M);
691
692  zz_pX NTLA= kronSubFp (A, d1);
693  zz_pX NTLB= kronSubFp (B, d1);
694
695  int k= d1*degree (M);
696  MulTrunc (NTLA, NTLA, NTLB, (long) k);
697
698  A= reverseSubstFp (NTLA, d1);
699
700  return A;
701}
702
703// assumes input to be reduced mod M and to be an element of Fq not Fp
704CanonicalForm
705mulMod2NTLFqReci (const CanonicalForm& F, const CanonicalForm& G, const
706                  CanonicalForm& M, const Variable& alpha)
707{
708  int d1= tmax (degree (F, 1), degree (G, 1)) + 1;
709  int d2= tmax (degree (F, 2), degree (G, 2));
710
711  zz_pEX F1, F2;
712  kronSubRecipro (F1, F2, F, d1, alpha);
713  zz_pEX G1, G2;
714  kronSubRecipro (G1, G2, G, d1, alpha);
715
716  int k1= d1*degree (M);
717  MulTrunc (F1, F1, G1, (long) k1);
718
719  mul (F2, F2, G2);
720
721  F2 >>= k1;
722
723  CanonicalForm result= reverseSubst (F1, F2, d1, d2, alpha);
724
725  return result;
726}
727
728CanonicalForm
729mulMod2NTLFq (const CanonicalForm& F, const CanonicalForm& G, const
730              CanonicalForm& M)
731{
732  Variable alpha;
733  CanonicalForm A= F;
734  CanonicalForm B= G;
735
736  if (hasFirstAlgVar (A, alpha) || hasFirstAlgVar (B, alpha))
737  {
738    int degAx= degree (A, 1);
739    int degAy= degree (A, 2);
740    int degBx= degree (B, 1);
741    int degBy= degree (B, 2);
742    int d1= degAx + degBx + 1;
743    int d2= tmax (degree (A, 2), degree (B, 2));
744    zz_p::init (getCharacteristic());
745    zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
746    zz_pE::init (NTLMipo);
747
748    int degMipo= degree (getMipo (alpha));
749    if ((d1 > 128/degMipo) && (d2 > 160/degMipo) && (degAy == degBy))
750      return mulMod2NTLFqReci (A, B, M, alpha);
751
752    zz_pEX NTLA= kronSub (A, d1, alpha);
753    zz_pEX NTLB= kronSub (B, d1, alpha);
754
755    int k= d1*degree (M);
756
757    MulTrunc (NTLA, NTLA, NTLB, (long) k);
758
759    A= reverseSubst (NTLA, d1, alpha);
760
761    return A;
762  }
763  else
764    return mulMod2NTLFp (A, B, M);
765}
766
767CanonicalForm mulMod2 (const CanonicalForm& A, const CanonicalForm& B,
768                       const CanonicalForm& M)
769{
770  if (A.isZero() || B.isZero())
771    return 0;
772
773  ASSERT (M.isUnivariate(), "M must be univariate");
774
775  CanonicalForm F= mod (A, M);
776  CanonicalForm G= mod (B, M);
777  if (F.inCoeffDomain() || G.inCoeffDomain())
778    return F*G;
779  Variable y= M.mvar();
780  int degF= degree (F, y);
781  int degG= degree (G, y);
782
783  if ((degF < 1 && degG < 1) && (F.isUnivariate() && G.isUnivariate()) &&
784      (F.level() == G.level()))
785  {
786    CanonicalForm result= mulNTL (F, G);
787    return mod (result, M);
788  }
789  else if (degF <= 1 && degG <= 1)
790  {
791    CanonicalForm result= F*G;
792    return mod (result, M);
793  }
794
795  int sizeF= size (F);
796  int sizeG= size (G);
797
798  int fallBackToNaive= 50;
799  if (sizeF < fallBackToNaive || sizeG < fallBackToNaive)
800    return mod (F*G, M);
801
802  if (getCharacteristic() > 0 && CFFactory::gettype() != GaloisFieldDomain &&
803      (((degF-degG) < 50 && degF > degG) || ((degG-degF) < 50 && degF <= degG)))
804    return mulMod2NTLFq (F, G, M);
805
806  int m= (int) ceil (degree (M)/2.0);
807  if (degF >= m || degG >= m)
808  {
809    CanonicalForm MLo= power (y, m);
810    CanonicalForm MHi= power (y, degree (M) - m);
811    CanonicalForm F0= mod (F, MLo);
812    CanonicalForm F1= div (F, MLo);
813    CanonicalForm G0= mod (G, MLo);
814    CanonicalForm G1= div (G, MLo);
815    CanonicalForm F0G1= mulMod2 (F0, G1, MHi);
816    CanonicalForm F1G0= mulMod2 (F1, G0, MHi);
817    CanonicalForm F0G0= mulMod2 (F0, G0, M);
818    return F0G0 + MLo*(F0G1 + F1G0);
819  }
820  else
821  {
822    m= (int) ceil (tmax (degF, degG)/2.0);
823    CanonicalForm yToM= power (y, m);
824    CanonicalForm F0= mod (F, yToM);
825    CanonicalForm F1= div (F, yToM);
826    CanonicalForm G0= mod (G, yToM);
827    CanonicalForm G1= div (G, yToM);
828    CanonicalForm H00= mulMod2 (F0, G0, M);
829    CanonicalForm H11= mulMod2 (F1, G1, M);
830    CanonicalForm H01= mulMod2 (F0 + F1, G0 + G1, M);
831    return H11*yToM*yToM + (H01 - H11 - H00)*yToM + H00;
832  }
833  DEBOUTLN (cerr, "fatal end in mulMod2");
834}
835
836CanonicalForm mulMod (const CanonicalForm& A, const CanonicalForm& B,
837                      const CFList& MOD)
838{
839  if (A.isZero() || B.isZero())
840    return 0;
841
842  if (MOD.length() == 1)
843    return mulMod2 (A, B, MOD.getLast());
844
845  CanonicalForm M= MOD.getLast();
846  CanonicalForm F= mod (A, M);
847  CanonicalForm G= mod (B, M);
848  if (F.inCoeffDomain() || G.inCoeffDomain())
849    return F*G;
850  Variable y= M.mvar();
851  int degF= degree (F, y);
852  int degG= degree (G, y);
853
854  if ((degF <= 1 && F.level() <= M.level()) &&
855      (degG <= 1 && G.level() <= M.level()))
856  {
857    CFList buf= MOD;
858    buf.removeLast();
859    if (degF == 1 && degG == 1)
860    {
861      CanonicalForm F0= mod (F, y);
862      CanonicalForm F1= div (F, y);
863      CanonicalForm G0= mod (G, y);
864      CanonicalForm G1= div (G, y);
865      if (degree (M) > 2)
866      {
867        CanonicalForm H00= mulMod (F0, G0, buf);
868        CanonicalForm H11= mulMod (F1, G1, buf);
869        CanonicalForm H01= mulMod (F0 + F1, G0 + G1, buf);
870        return H11*y*y + (H01 - H00 - H11)*y + H00;
871      }
872      else //here degree (M) == 2
873      {
874        buf.append (y);
875        CanonicalForm F0G1= mulMod (F0, G1, buf);
876        CanonicalForm F1G0= mulMod (F1, G0, buf);
877        CanonicalForm F0G0= mulMod (F0, G0, MOD);
878        CanonicalForm result= F0G0 + y*(F0G1 + F1G0);
879        return result;
880      }
881    }
882    else if (degF == 1 && degG == 0)
883      return mulMod (div (F, y), G, buf)*y + mulMod (mod (F, y), G, buf);
884    else if (degF == 0 && degG == 1)
885      return mulMod (div (G, y), F, buf)*y + mulMod (mod (G, y), F, buf);
886    else
887      return mulMod (F, G, buf);
888  }
889  int m= (int) ceil (degree (M)/2.0);
890  if (degF >= m || degG >= m)
891  {
892    CanonicalForm MLo= power (y, m);
893    CanonicalForm MHi= power (y, degree (M) - m);
894    CanonicalForm F0= mod (F, MLo);
895    CanonicalForm F1= div (F, MLo);
896    CanonicalForm G0= mod (G, MLo);
897    CanonicalForm G1= div (G, MLo);
898    CFList buf= MOD;
899    buf.removeLast();
900    buf.append (MHi);
901    CanonicalForm F0G1= mulMod (F0, G1, buf);
902    CanonicalForm F1G0= mulMod (F1, G0, buf);
903    CanonicalForm F0G0= mulMod (F0, G0, MOD);
904    return F0G0 + MLo*(F0G1 + F1G0);
905  }
906  else
907  {
908    m= (int) ceil (tmax (degF, degG)/2.0);
909    CanonicalForm yToM= power (y, m);
910    CanonicalForm F0= mod (F, yToM);
911    CanonicalForm F1= div (F, yToM);
912    CanonicalForm G0= mod (G, yToM);
913    CanonicalForm G1= div (G, yToM);
914    CanonicalForm H00= mulMod (F0, G0, MOD);
915    CanonicalForm H11= mulMod (F1, G1, MOD);
916    CanonicalForm H01= mulMod (F0 + F1, G0 + G1, MOD);
917    return H11*yToM*yToM + (H01 - H11 - H00)*yToM + H00;
918  }
919  DEBOUTLN (cerr, "fatal end in mulMod");
920}
921
922CanonicalForm prodMod (const CFList& L, const CanonicalForm& M)
923{
924  if (L.isEmpty())
925    return 1;
926  int l= L.length();
927  if (l == 1)
928    return mod (L.getFirst(), M);
929  else if (l == 2) {
930    CanonicalForm result= mulMod2 (L.getFirst(), L.getLast(), M);
931    return result;
932  }
933  else
934  {
935    l /= 2;
936    CFList tmp1, tmp2;
937    CFListIterator i= L;
938    CanonicalForm buf1, buf2;
939    for (int j= 1; j <= l; j++, i++)
940      tmp1.append (i.getItem());
941    tmp2= Difference (L, tmp1);
942    buf1= prodMod (tmp1, M);
943    buf2= prodMod (tmp2, M);
944    CanonicalForm result= mulMod2 (buf1, buf2, M);
945    return result;
946  }
947}
948
949CanonicalForm prodMod (const CFList& L, const CFList& M)
950{
951  if (L.isEmpty())
952    return 1;
953  else if (L.length() == 1)
954    return L.getFirst();
955  else if (L.length() == 2)
956    return mulMod (L.getFirst(), L.getLast(), M);
957  else
958  {
959    int l= L.length()/2;
960    CFListIterator i= L;
961    CFList tmp1, tmp2;
962    CanonicalForm buf1, buf2;
963    for (int j= 1; j <= l; j++, i++)
964      tmp1.append (i.getItem());
965    tmp2= Difference (L, tmp1);
966    buf1= prodMod (tmp1, M);
967    buf2= prodMod (tmp2, M);
968    return mulMod (buf1, buf2, M);
969  }
970}
971
972
973CanonicalForm reverse (const CanonicalForm& F, int d)
974{
975  if (d == 0)
976    return F;
977  CanonicalForm A= F;
978  Variable y= Variable (2);
979  Variable x= Variable (1);
980  if (degree (A, x) > 0)
981  {
982    A= swapvar (A, x, y);
983    CanonicalForm result= 0;
984    CFIterator i= A;
985    while (d - i.exp() < 0)
986      i++;
987
988    for (; i.hasTerms() && (d - i.exp() >= 0); i++)
989      result += swapvar (i.coeff(),x,y)*power (x, d - i.exp());
990    return result;
991  }
992  else
993    return A*power (x, d);
994}
995
996CanonicalForm
997newtonInverse (const CanonicalForm& F, const int n, const CanonicalForm& M)
998{
999  int l= ilog2(n);
1000
1001  CanonicalForm g= mod (F, M)[0] [0];
1002
1003  ASSERT (!g.isZero(), "expected a unit");
1004
1005  Variable alpha;
1006
1007  if (!g.isOne())
1008    g = 1/g;
1009  Variable x= Variable (1);
1010  CanonicalForm result;
1011  int exp= 0;
1012  if (n & 1)
1013  {
1014    result= g;
1015    exp= 1;
1016  }
1017  CanonicalForm h;
1018
1019  for (int i= 1; i <= l; i++)
1020  {
1021    h= mulMod2 (g, mod (F, power (x, (1 << i))), M);
1022    h= mod (h, power (x, (1 << i)) - 1);
1023    h= div (h, power (x, (1 << (i - 1))));
1024    h= mod (h, M);
1025    g -= power (x, (1 << (i - 1)))*
1026         mod (mulMod2 (g, h, M), power (x, (1 << (i - 1))));
1027
1028    if (n & (1 << i))
1029    {
1030      if (exp)
1031      {
1032        h= mulMod2 (result, mod (F, power (x, exp + (1 << i))), M);
1033        h= mod (h, power (x, exp + (1 << i)) - 1);
1034        h= div (h, power (x, exp));
1035        h= mod (h, M);
1036        result -= power(x, exp)*mod (mulMod2 (g, h, M),
1037                                       power (x, (1 << i)));
1038        exp += (1 << i);
1039      }
1040      else
1041      {
1042        exp= (1 << i);
1043        result= g;
1044      }
1045    }
1046  }
1047
1048  return result;
1049}
1050
1051CanonicalForm
1052newtonDiv (const CanonicalForm& F, const CanonicalForm& G, const CanonicalForm&
1053           M)
1054{
1055  ASSERT (getCharacteristic() > 0, "positive characteristic expected");
1056  ASSERT (CFFactory::gettype() != GaloisFieldDomain, "no GF expected");
1057
1058  CanonicalForm A= mod (F, M);
1059  CanonicalForm B= mod (G, M);
1060
1061  Variable x= Variable (1);
1062  int degA= degree (A, x);
1063  int degB= degree (B, x);
1064  int m= degA - degB;
1065  if (m < 0)
1066    return 0;
1067
1068  CanonicalForm Q;
1069  if (degB <= 1 || CFFactory::gettype() == GaloisFieldDomain)
1070  {
1071    CanonicalForm R;
1072    divrem2 (A, B, Q, R, M);
1073  }
1074  else
1075  {
1076    CanonicalForm R= reverse (A, degA);
1077    CanonicalForm revB= reverse (B, degB);
1078    revB= newtonInverse (revB, m + 1, M);
1079    Q= mulMod2 (R, revB, M);
1080    Q= mod (Q, power (x, m + 1));
1081    Q= reverse (Q, m);
1082  }
1083
1084  return Q;
1085}
1086
1087void
1088newtonDivrem (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
1089              CanonicalForm& R, const CanonicalForm& M)
1090{
1091  CanonicalForm A= mod (F, M);
1092  CanonicalForm B= mod (G, M);
1093  Variable x= Variable (1);
1094  int degA= degree (A, x);
1095  int degB= degree (B, x);
1096  int m= degA - degB;
1097
1098  if (m < 0)
1099  {
1100    R= A;
1101    Q= 0;
1102    return;
1103  }
1104
1105  if (degB <= 1 || CFFactory::gettype() == GaloisFieldDomain)
1106  {
1107     divrem2 (A, B, Q, R, M);
1108  }
1109  else
1110  {
1111    R= reverse (A, degA);
1112
1113    CanonicalForm revB= reverse (B, degB);
1114    revB= newtonInverse (revB, m + 1, M);
1115    Q= mulMod2 (R, revB, M);
1116
1117    Q= mod (Q, power (x, m + 1));
1118    Q= reverse (Q, m);
1119
1120    R= A - mulMod2 (Q, B, M);
1121  }
1122}
1123
1124static inline
1125CFList split (const CanonicalForm& F, const int m, const Variable& x)
1126{
1127  CanonicalForm A= F;
1128  CanonicalForm buf= 0;
1129  bool swap= false;
1130  if (degree (A, x) <= 0)
1131    return CFList(A);
1132  else if (x.level() != A.level())
1133  {
1134    swap= true;
1135    A= swapvar (A, x, A.mvar());
1136  }
1137
1138  int j= (int) floor ((double) degree (A)/ m);
1139  CFList result;
1140  CFIterator i= A;
1141  for (; j >= 0; j--)
1142  {
1143    while (i.hasTerms() && i.exp() - j*m >= 0)
1144    {
1145      if (swap)
1146        buf += i.coeff()*power (A.mvar(), i.exp() - j*m);
1147      else
1148        buf += i.coeff()*power (x, i.exp() - j*m);
1149      i++;
1150    }
1151    if (swap)
1152      result.append (swapvar (buf, x, F.mvar()));
1153    else
1154      result.append (buf);
1155    buf= 0;
1156  }
1157  return result;
1158}
1159
1160static inline
1161void divrem32 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
1162               CanonicalForm& R, const CFList& M);
1163
1164static inline
1165void divrem21 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
1166               CanonicalForm& R, const CFList& M)
1167{
1168  CanonicalForm A= mod (F, M);
1169  CanonicalForm B= mod (G, M);
1170  Variable x= Variable (1);
1171  int degB= degree (B, x);
1172  int degA= degree (A, x);
1173  if (degA < degB)
1174  {
1175    Q= 0;
1176    R= A;
1177    return;
1178  }
1179  ASSERT (2*degB > degA, "expected degree (F, 1) < 2*degree (G, 1)");
1180  if (degB < 1)
1181  {
1182    divrem (A, B, Q, R);
1183    Q= mod (Q, M);
1184    R= mod (R, M);
1185    return;
1186  }
1187
1188  int m= (int) ceil ((double) (degB + 1)/2.0) + 1;
1189  CFList splitA= split (A, m, x);
1190  if (splitA.length() == 3)
1191    splitA.insert (0);
1192  if (splitA.length() == 2)
1193  {
1194    splitA.insert (0);
1195    splitA.insert (0);
1196  }
1197  if (splitA.length() == 1)
1198  {
1199    splitA.insert (0);
1200    splitA.insert (0);
1201    splitA.insert (0);
1202  }
1203
1204  CanonicalForm xToM= power (x, m);
1205
1206  CFListIterator i= splitA;
1207  CanonicalForm H= i.getItem();
1208  i++;
1209  H *= xToM;
1210  H += i.getItem();
1211  i++;
1212  H *= xToM;
1213  H += i.getItem();
1214  i++;
1215
1216  divrem32 (H, B, Q, R, M);
1217
1218  CFList splitR= split (R, m, x);
1219  if (splitR.length() == 1)
1220    splitR.insert (0);
1221
1222  H= splitR.getFirst();
1223  H *= xToM;
1224  H += splitR.getLast();
1225  H *= xToM;
1226  H += i.getItem();
1227
1228  CanonicalForm bufQ;
1229  divrem32 (H, B, bufQ, R, M);
1230
1231  Q *= xToM;
1232  Q += bufQ;
1233  return;
1234}
1235
1236static inline
1237void divrem32 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
1238               CanonicalForm& R, const CFList& M)
1239{
1240  CanonicalForm A= mod (F, M);
1241  CanonicalForm B= mod (G, M);
1242  Variable x= Variable (1);
1243  int degB= degree (B, x);
1244  int degA= degree (A, x);
1245  if (degA < degB)
1246  {
1247    Q= 0;
1248    R= A;
1249    return;
1250  }
1251  ASSERT (3*(degB/2) > degA, "expected degree (F, 1) < 3*(degree (G, 1)/2)");
1252  if (degB < 1)
1253  {
1254    divrem (A, B, Q, R);
1255    Q= mod (Q, M);
1256    R= mod (R, M);
1257    return;
1258  }
1259  int m= (int) ceil ((double) (degB + 1)/ 2.0);
1260
1261  CFList splitA= split (A, m, x);
1262  CFList splitB= split (B, m, x);
1263
1264  if (splitA.length() == 2)
1265  {
1266    splitA.insert (0);
1267  }
1268  if (splitA.length() == 1)
1269  {
1270    splitA.insert (0);
1271    splitA.insert (0);
1272  }
1273  CanonicalForm xToM= power (x, m);
1274
1275  CanonicalForm H;
1276  CFListIterator i= splitA;
1277  i++;
1278
1279  if (degree (splitA.getFirst(), x) < degree (splitB.getFirst(), x))
1280  {
1281    H= splitA.getFirst()*xToM + i.getItem();
1282    divrem21 (H, splitB.getFirst(), Q, R, M);
1283  }
1284  else
1285  {
1286    R= splitA.getFirst()*xToM + i.getItem() + splitB.getFirst() -
1287       splitB.getFirst()*xToM;
1288    Q= xToM - 1;
1289  }
1290
1291  H= mulMod (Q, splitB.getLast(), M);
1292
1293  R= R*xToM + splitA.getLast() - H;
1294
1295  while (degree (R, x) >= degB)
1296  {
1297    xToM= power (x, degree (R, x) - degB);
1298    Q += LC (R, x)*xToM;
1299    R -= mulMod (LC (R, x), B, M)*xToM;
1300    Q= mod (Q, M);
1301    R= mod (R, M);
1302  }
1303
1304  return;
1305}
1306
1307void divrem2 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
1308              CanonicalForm& R, const CanonicalForm& M)
1309{
1310  CanonicalForm A= mod (F, M);
1311  CanonicalForm B= mod (G, M);
1312
1313  if (B.inCoeffDomain())
1314  {
1315    divrem (A, B, Q, R);
1316    return;
1317  }
1318  if (A.inCoeffDomain() && !B.inCoeffDomain())
1319  {
1320    Q= 0;
1321    R= A;
1322    return;
1323  }
1324
1325  if (B.level() < A.level())
1326  {
1327    divrem (A, B, Q, R);
1328    return;
1329  }
1330  if (A.level() > B.level())
1331  {
1332    R= A;
1333    Q= 0;
1334    return;
1335  }
1336  if (B.level() == 1 && B.isUnivariate())
1337  {
1338    divrem (A, B, Q, R);
1339    return;
1340  }
1341  if (!(B.level() == 1 && B.isUnivariate()) && (A.level() == 1 && A.isUnivariate()))
1342  {
1343    Q= 0;
1344    R= A;
1345    return;
1346  }
1347
1348  Variable x= Variable (1);
1349  int degB= degree (B, x);
1350  if (degB > degree (A, x))
1351  {
1352    Q= 0;
1353    R= A;
1354    return;
1355  }
1356
1357  CFList splitA= split (A, degB, x);
1358
1359  CanonicalForm xToDegB= power (x, degB);
1360  CanonicalForm H, bufQ;
1361  Q= 0;
1362  CFListIterator i= splitA;
1363  H= i.getItem()*xToDegB;
1364  i++;
1365  H += i.getItem();
1366  CFList buf;
1367  while (i.hasItem())
1368  {
1369    buf= CFList (M);
1370    divrem21 (H, B, bufQ, R, buf);
1371    i++;
1372    if (i.hasItem())
1373      H= R*xToDegB + i.getItem();
1374    Q *= xToDegB;
1375    Q += bufQ;
1376  }
1377  return;
1378}
1379
1380void divrem (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
1381             CanonicalForm& R, const CFList& MOD)
1382{
1383  CanonicalForm A= mod (F, MOD);
1384  CanonicalForm B= mod (G, MOD);
1385  Variable x= Variable (1);
1386  int degB= degree (B, x);
1387  if (degB > degree (A, x))
1388  {
1389    Q= 0;
1390    R= A;
1391    return;
1392  }
1393
1394  if (degB <= 0)
1395  {
1396    divrem (A, B, Q, R);
1397    Q= mod (Q, MOD);
1398    R= mod (R, MOD);
1399    return;
1400  }
1401  CFList splitA= split (A, degB, x);
1402
1403  CanonicalForm xToDegB= power (x, degB);
1404  CanonicalForm H, bufQ;
1405  Q= 0;
1406  CFListIterator i= splitA;
1407  H= i.getItem()*xToDegB;
1408  i++;
1409  H += i.getItem();
1410  while (i.hasItem())
1411  {
1412    divrem21 (H, B, bufQ, R, MOD);
1413    i++;
1414    if (i.hasItem())
1415      H= R*xToDegB + i.getItem();
1416    Q *= xToDegB;
1417    Q += bufQ;
1418  }
1419  return;
1420}
1421
1422void sortList (CFList& list, const Variable& x)
1423{
1424  int l= 1;
1425  int k= 1;
1426  CanonicalForm buf;
1427  CFListIterator m;
1428  for (CFListIterator i= list; l <= list.length(); i++, l++)
1429  {
1430    for (CFListIterator j= list; k <= list.length() - l; k++)
1431    {
1432      m= j;
1433      m++;
1434      if (degree (j.getItem(), x) > degree (m.getItem(), x))
1435      {
1436        buf= m.getItem();
1437        m.getItem()= j.getItem();
1438        j.getItem()= buf;
1439        j++;
1440        j.getItem()= m.getItem();
1441      }
1442      else
1443        j++;
1444    }
1445    k= 1;
1446  }
1447}
1448
1449static inline
1450CFList diophantine (const CanonicalForm& F, const CFList& factors)
1451{
1452  CanonicalForm buf1, buf2, buf3, S, T;
1453  CFListIterator i= factors;
1454  CFList result;
1455  if (i.hasItem())
1456    i++;
1457  buf1= F/factors.getFirst();
1458  buf2= divNTL (F, i.getItem());
1459  buf3= extgcd (buf1, buf2, S, T);
1460  result.append (S);
1461  result.append (T);
1462  if (i.hasItem())
1463    i++;
1464  for (; i.hasItem(); i++)
1465  {
1466    buf1= divNTL (F, i.getItem());
1467    buf3= extgcd (buf3, buf1, S, T);
1468    CFListIterator k= factors;
1469    for (CFListIterator j= result; j.hasItem(); j++, k++)
1470    {
1471      j.getItem()= mulNTL (j.getItem(), S);
1472      j.getItem()= modNTL (j.getItem(), k.getItem());
1473    }
1474    result.append (T);
1475  }
1476  return result;
1477}
1478
1479void
1480henselStep12 (const CanonicalForm& F, const CFList& factors,
1481              CFArray& bufFactors, const CFList& diophant, CFMatrix& M,
1482              CFArray& Pi, int j)
1483{
1484  CanonicalForm E;
1485  CanonicalForm xToJ= power (F.mvar(), j);
1486  Variable x= F.mvar();
1487  // compute the error
1488  if (j == 1)
1489    E= F[j];
1490  else
1491  {
1492    if (degree (Pi [factors.length() - 2], x) > 0)
1493      E= F[j] - Pi [factors.length() - 2] [j];
1494    else
1495      E= F[j];
1496  }
1497
1498  CFArray buf= CFArray (diophant.length());
1499  bufFactors[0]= mod (factors.getFirst(), power (F.mvar(), j + 1));
1500  int k= 0;
1501  CanonicalForm remainder;
1502  // actual lifting
1503  for (CFListIterator i= diophant; i.hasItem(); i++, k++)
1504  {
1505    if (degree (bufFactors[k], x) > 0)
1506    {
1507      if (k > 0)
1508        remainder= modNTL (E, bufFactors[k] [0]);
1509      else
1510        remainder= E;
1511    }
1512    else
1513      remainder= modNTL (E, bufFactors[k]);
1514
1515    buf[k]= mulNTL (i.getItem(), remainder);
1516    if (degree (bufFactors[k], x) > 0)
1517      buf[k]= modNTL (buf[k], bufFactors[k] [0]);
1518    else
1519      buf[k]= modNTL (buf[k], bufFactors[k]);
1520  }
1521  for (k= 1; k < factors.length(); k++)
1522    bufFactors[k] += xToJ*buf[k];
1523
1524  // update Pi [0]
1525  int degBuf0= degree (bufFactors[0], x);
1526  int degBuf1= degree (bufFactors[1], x);
1527  if (degBuf0 > 0 && degBuf1 > 0)
1528    M (j + 1, 1)= mulNTL (bufFactors[0] [j], bufFactors[1] [j]);
1529  CanonicalForm uIZeroJ;
1530  if (j == 1)
1531  {
1532    if (degBuf0 > 0 && degBuf1 > 0)
1533      uIZeroJ= mulNTL ((bufFactors[0] [0] + bufFactors[0] [j]),
1534                  (bufFactors[1] [0] + buf[1])) - M(1, 1) - M(j + 1, 1);
1535    else if (degBuf0 > 0)
1536      uIZeroJ= mulNTL (bufFactors[0] [j], bufFactors[1]);
1537    else if (degBuf1 > 0)
1538      uIZeroJ= mulNTL (bufFactors[0], buf[1]);
1539    else
1540      uIZeroJ= 0;
1541    Pi [0] += xToJ*uIZeroJ;
1542  }
1543  else
1544  {
1545    if (degBuf0 > 0 && degBuf1 > 0)
1546      uIZeroJ= mulNTL ((bufFactors[0] [0] + bufFactors[0] [j]),
1547                  (bufFactors[1] [0] + buf[1])) - M(1, 1) - M(j + 1, 1);
1548    else if (degBuf0 > 0)
1549      uIZeroJ= mulNTL (bufFactors[0] [j], bufFactors[1]);
1550    else if (degBuf1 > 0)
1551      uIZeroJ= mulNTL (bufFactors[0], buf[1]);
1552    else
1553      uIZeroJ= 0;
1554    Pi [0] += xToJ*uIZeroJ;
1555  }
1556  CFArray tmp= CFArray (factors.length() - 1);
1557  for (k= 0; k < factors.length() - 1; k++)
1558    tmp[k]= 0;
1559  CFIterator one, two;
1560  one= bufFactors [0];
1561  two= bufFactors [1];
1562  if (degBuf0 > 0 && degBuf1 > 0)
1563  {
1564    for (k= 1; k <= (int) ceil (j/2.0); k++)
1565    {
1566      if (k != j - k + 1)
1567      {
1568        if ((one.hasTerms() && one.exp() == j - k + 1) && (two.hasTerms() && two.exp() == j - k + 1))
1569        {
1570          tmp[0] += mulNTL ((bufFactors[0] [k] + one.coeff()), (bufFactors[1] [k] +
1571                     two.coeff())) - M (k + 1, 1) - M (j - k + 2, 1);
1572          one++;
1573          two++;
1574        }
1575        else if (one.hasTerms() && one.exp() == j - k + 1)
1576        {
1577          tmp[0] += mulNTL ((bufFactors[0] [k] + one.coeff()), bufFactors[1] [k]) -
1578                     M (k + 1, 1);
1579          one++;
1580        }
1581        else if (two.hasTerms() && two.exp() == j - k + 1)
1582        {
1583          tmp[0] += mulNTL (bufFactors[0] [k], (bufFactors[1] [k] + two.coeff())) -
1584                    M (k + 1, 1);
1585          two++;
1586        }
1587      }
1588      else
1589      {
1590        tmp[0] += M (k + 1, 1);
1591      }
1592    }
1593  }
1594  Pi [0] += tmp[0]*xToJ*F.mvar();
1595
1596  // update Pi [l]
1597  int degPi, degBuf;
1598  for (int l= 1; l < factors.length() - 1; l++)
1599  {
1600    degPi= degree (Pi [l - 1], x);
1601    degBuf= degree (bufFactors[l + 1], x);
1602    if (degPi > 0 && degBuf > 0)
1603      M (j + 1, l + 1)= mulNTL (Pi [l - 1] [j], bufFactors[l + 1] [j]);
1604    if (j == 1)
1605    {
1606      if (degPi > 0 && degBuf > 0)
1607        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [0] + Pi [l - 1] [j],
1608                  bufFactors[l + 1] [0] + buf[l + 1]) - M (j + 1, l +1) -
1609                  M (1, l + 1));
1610      else if (degPi > 0)
1611        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [j], bufFactors[l + 1]));
1612      else if (degBuf > 0)
1613        Pi [l] += xToJ*(mulNTL (Pi [l - 1], buf[l + 1]));
1614    }
1615    else
1616    {
1617      if (degPi > 0 && degBuf > 0)
1618      {
1619        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
1620        uIZeroJ += mulNTL (Pi [l - 1] [0], buf [l + 1]);
1621      }
1622      else if (degPi > 0)
1623        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1]);
1624      else if (degBuf > 0)
1625      {
1626        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
1627        uIZeroJ += mulNTL (Pi [l - 1], buf[l + 1]);
1628      }
1629      Pi[l] += xToJ*uIZeroJ;
1630    }
1631    one= bufFactors [l + 1];
1632    two= Pi [l - 1];
1633    if (two.hasTerms() && two.exp() == j + 1)
1634    {
1635      if (degBuf > 0 && degPi > 0)
1636      {
1637          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1][0]);
1638          two++;
1639      }
1640      else if (degPi > 0)
1641      {
1642          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1]);
1643          two++;
1644      }
1645    }
1646    if (degBuf > 0 && degPi > 0)
1647    {
1648      for (k= 1; k <= (int) ceil (j/2.0); k++)
1649      {
1650        if (k != j - k + 1)
1651        {
1652          if ((one.hasTerms() && one.exp() == j - k + 1) &&
1653              (two.hasTerms() && two.exp() == j - k + 1))
1654          {
1655            tmp[l] += mulNTL ((bufFactors[l + 1] [k] + one.coeff()), (Pi[l - 1] [k] +
1656                       two.coeff())) - M (k + 1, l + 1) - M (j - k + 2, l + 1);
1657            one++;
1658            two++;
1659          }
1660          else if (one.hasTerms() && one.exp() == j - k + 1)
1661          {
1662            tmp[l] += mulNTL ((bufFactors[l + 1] [k] + one.coeff()), Pi[l - 1] [k]) -
1663                       M (k + 1, l + 1);
1664            one++;
1665          }
1666          else if (two.hasTerms() && two.exp() == j - k + 1)
1667          {
1668            tmp[l] += mulNTL (bufFactors[l + 1] [k], (Pi[l - 1] [k] + two.coeff())) -
1669                      M (k + 1, l + 1);
1670            two++;
1671          }
1672        }
1673        else
1674          tmp[l] += M (k + 1, l + 1);
1675      }
1676    }
1677    Pi[l] += tmp[l]*xToJ*F.mvar();
1678  }
1679  return;
1680}
1681
1682void
1683henselLift12 (const CanonicalForm& F, CFList& factors, int l, CFArray& Pi,
1684              CFList& diophant, CFMatrix& M, bool sort)
1685{
1686  if (sort)
1687    sortList (factors, Variable (1));
1688  Pi= CFArray (factors.length() - 1);
1689  CFListIterator j= factors;
1690  diophant= diophantine (F[0], factors);
1691  DEBOUTLN (cerr, "diophant= " << diophant);
1692  j++;
1693  Pi [0]= mulNTL (j.getItem(), mod (factors.getFirst(), F.mvar()));
1694  M (1, 1)= Pi [0];
1695  int i= 1;
1696  if (j.hasItem())
1697    j++;
1698  for (; j.hasItem(); j++, i++)
1699  {
1700    Pi [i]= mulNTL (Pi [i - 1], j.getItem());
1701    M (1, i + 1)= Pi [i];
1702  }
1703  CFArray bufFactors= CFArray (factors.length());
1704  i= 0;
1705  for (CFListIterator k= factors; k.hasItem(); i++, k++)
1706  {
1707    if (i == 0)
1708      bufFactors[i]= mod (k.getItem(), F.mvar());
1709    else
1710      bufFactors[i]= k.getItem();
1711  }
1712  for (i= 1; i < l; i++)
1713    henselStep12 (F, factors, bufFactors, diophant, M, Pi, i);
1714
1715  CFListIterator k= factors;
1716  for (i= 0; i < factors.length (); i++, k++)
1717    k.getItem()= bufFactors[i];
1718  factors.removeFirst();
1719  return;
1720}
1721
1722void
1723henselLiftResume12 (const CanonicalForm& F, CFList& factors, int start, int
1724                    end, CFArray& Pi, const CFList& diophant, CFMatrix& M)
1725{
1726  CFArray bufFactors= CFArray (factors.length());
1727  int i= 0;
1728  CanonicalForm xToStart= power (F.mvar(), start);
1729  for (CFListIterator k= factors; k.hasItem(); k++, i++)
1730  {
1731    if (i == 0)
1732      bufFactors[i]= mod (k.getItem(), xToStart);
1733    else
1734      bufFactors[i]= k.getItem();
1735  }
1736  for (i= start; i < end; i++)
1737    henselStep12 (F, factors, bufFactors, diophant, M, Pi, i);
1738
1739  CFListIterator k= factors;
1740  for (i= 0; i < factors.length(); k++, i++)
1741    k.getItem()= bufFactors [i];
1742  factors.removeFirst();
1743  return;
1744}
1745
1746static inline
1747CFList
1748biDiophantine (const CanonicalForm& F, const CFList& factors, const int d)
1749{
1750  Variable y= F.mvar();
1751  CFList result;
1752  if (y.level() == 1)
1753  {
1754    result= diophantine (F, factors);
1755    return result;
1756  }
1757  else
1758  {
1759    CFList buf= factors;
1760    for (CFListIterator i= buf; i.hasItem(); i++)
1761      i.getItem()= mod (i.getItem(), y);
1762    CanonicalForm A= mod (F, y);
1763    int bufD= 1;
1764    CFList recResult= biDiophantine (A, buf, bufD);
1765    CanonicalForm e= 1;
1766    CFList p;
1767    CFArray bufFactors= CFArray (factors.length());
1768    CanonicalForm yToD= power (y, d);
1769    int k= 0;
1770    for (CFListIterator i= factors; i.hasItem(); i++, k++)
1771    {
1772      bufFactors [k]= i.getItem();
1773    }
1774    CanonicalForm b;
1775    for (k= 0; k < factors.length(); k++) //TODO compute b's faster
1776    {
1777      b= 1;
1778      if (fdivides (bufFactors[k], F))
1779        b= F/bufFactors[k];
1780      else
1781      {
1782        for (int l= 0; l < factors.length(); l++)
1783        {
1784          if (l == k)
1785            continue;
1786          else
1787          {
1788            b= mulMod2 (b, bufFactors[l], yToD);
1789          }
1790        }
1791      }
1792      p.append (b);
1793    }
1794
1795    CFListIterator j= p;
1796    for (CFListIterator i= recResult; i.hasItem(); i++, j++)
1797      e -= i.getItem()*j.getItem();
1798
1799    if (e.isZero())
1800      return recResult;
1801    CanonicalForm coeffE;
1802    CFList s;
1803    result= recResult;
1804    CanonicalForm g;
1805    for (int i= 1; i < d; i++)
1806    {
1807      if (degree (e, y) > 0)
1808        coeffE= e[i];
1809      else
1810        coeffE= 0;
1811      if (!coeffE.isZero())
1812      {
1813        CFListIterator k= result;
1814        CFListIterator l= p;
1815        int ii= 0;
1816        j= recResult;
1817        for (; j.hasItem(); j++, k++, l++, ii++)
1818        {
1819          g= coeffE*j.getItem();
1820          if (degree (bufFactors[ii], y) <= 0)
1821            g= mod (g, bufFactors[ii]);
1822          else
1823            g= mod (g, bufFactors[ii][0]);
1824          k.getItem() += g*power (y, i);
1825          e -= mulMod2 (g*power(y, i), l.getItem(), yToD);
1826          DEBOUTLN (cerr, "mod (e, power (y, i + 1))= " <<
1827                    mod (e, power (y, i + 1)));
1828        }
1829      }
1830      if (e.isZero())
1831        break;
1832    }
1833
1834    DEBOUTLN (cerr, "mod (e, y)= " << mod (e, y));
1835
1836#ifdef DEBUGOUTPUT
1837    CanonicalForm test= 0;
1838    j= p;
1839    for (CFListIterator i= result; i.hasItem(); i++, j++)
1840      test += mod (i.getItem()*j.getItem(), power (y, d));
1841    DEBOUTLN (cerr, "test= " << test);
1842#endif
1843    return result;
1844  }
1845}
1846
1847static inline
1848CFList
1849multiRecDiophantine (const CanonicalForm& F, const CFList& factors,
1850                     const CFList& recResult, const CFList& M, const int d)
1851{
1852  Variable y= F.mvar();
1853  CFList result;
1854  CFListIterator i;
1855  CanonicalForm e= 1;
1856  CFListIterator j= factors;
1857  CFList p;
1858  CFArray bufFactors= CFArray (factors.length());
1859  CanonicalForm yToD= power (y, d);
1860  int k= 0;
1861  for (CFListIterator i= factors; i.hasItem(); i++, k++)
1862    bufFactors [k]= i.getItem();
1863  CanonicalForm b;
1864  CFList buf= M;
1865  buf.removeLast();
1866  buf.append (yToD);
1867  for (k= 0; k < factors.length(); k++) //TODO compute b's faster
1868  {
1869    b= 1;
1870    if (fdivides (bufFactors[k], F))
1871      b= F/bufFactors[k];
1872    else
1873    {
1874      for (int l= 0; l < factors.length(); l++)
1875      {
1876        if (l == k)
1877          continue;
1878        else
1879        {
1880          b= mulMod (b, bufFactors[l], buf);
1881        }
1882      }
1883    }
1884    p.append (b);
1885  }
1886  j= p;
1887  for (CFListIterator i= recResult; i.hasItem(); i++, j++)
1888    e -= mulMod (i.getItem(), j.getItem(), M);
1889
1890  if (e.isZero())
1891    return recResult;
1892  CanonicalForm coeffE;
1893  CFList s;
1894  result= recResult;
1895  CanonicalForm g;
1896  for (int i= 1; i < d; i++)
1897  {
1898    if (degree (e, y) > 0)
1899      coeffE= e[i];
1900    else
1901      coeffE= 0;
1902    if (!coeffE.isZero())
1903    {
1904      CFListIterator k= result;
1905      CFListIterator l= p;
1906      j= recResult;
1907      int ii= 0;
1908      CanonicalForm dummy;
1909      for (; j.hasItem(); j++, k++, l++, ii++)
1910      {
1911        g= mulMod (coeffE, j.getItem(), M);
1912        if (degree (bufFactors[ii], y) <= 0)
1913          divrem (g, mod (bufFactors[ii], Variable (y.level() - 1)), dummy,
1914                  g, M);
1915        else
1916          divrem (g, bufFactors[ii][0], dummy, g, M);
1917        k.getItem() += g*power (y, i);
1918        e -= mulMod (g*power (y, i), l.getItem(), M);
1919      }
1920    }
1921
1922    if (e.isZero())
1923      break;
1924  }
1925
1926#ifdef DEBUGOUTPUT
1927    CanonicalForm test= 0;
1928    j= p;
1929    for (CFListIterator i= result; i.hasItem(); i++, j++)
1930      test += mod (i.getItem()*j.getItem(), power (y, d));
1931    DEBOUTLN (cerr, "test= " << test);
1932#endif
1933  return result;
1934}
1935
1936static inline
1937void
1938henselStep (const CanonicalForm& F, const CFList& factors, CFArray& bufFactors,
1939            const CFList& diophant, CFMatrix& M, CFArray& Pi, int j,
1940            const CFList& MOD)
1941{
1942  CanonicalForm E;
1943  CanonicalForm xToJ= power (F.mvar(), j);
1944  Variable x= F.mvar();
1945  // compute the error
1946  if (j == 1)
1947  {
1948    E= F[j];
1949#ifdef DEBUGOUTPUT
1950    CanonicalForm test= 1;
1951    for (int i= 0; i < factors.length(); i++)
1952    {
1953      if (i == 0)
1954        test= mulMod (test, mod (bufFactors [i], xToJ), MOD);
1955      else
1956        test= mulMod (test, bufFactors[i], MOD);
1957    }
1958    CanonicalForm test2= mod (F-test, xToJ);
1959
1960    test2= mod (test2, MOD);
1961    DEBOUTLN (cerr, "test= " << test2);
1962#endif
1963  }
1964  else
1965  {
1966#ifdef DEBUGOUTPUT
1967    CanonicalForm test= 1;
1968    for (int i= 0; i < factors.length(); i++)
1969    {
1970      if (i == 0)
1971        test *= mod (bufFactors [i], power (x, j));
1972      else
1973        test *= bufFactors[i];
1974    }
1975    test= mod (test, power (x, j));
1976    test= mod (test, MOD);
1977    CanonicalForm test2= mod (F, power (x, j - 1)) - mod (test, power (x, j-1));
1978    DEBOUTLN (cerr, "test= " << test2);
1979#endif
1980
1981    if (degree (Pi [factors.length() - 2], x) > 0)
1982      E= F[j] - Pi [factors.length() - 2] [j];
1983    else
1984      E= F[j];
1985  }
1986
1987  CFArray buf= CFArray (diophant.length());
1988  bufFactors[0]= mod (factors.getFirst(), power (F.mvar(), j + 1));
1989  int k= 0;
1990  // actual lifting
1991  CanonicalForm dummy, rest1;
1992  for (CFListIterator i= diophant; i.hasItem(); i++, k++)
1993  {
1994    if (degree (bufFactors[k], x) > 0)
1995    {
1996      if (k > 0)
1997        divrem (E, bufFactors[k] [0], dummy, rest1, MOD);
1998      else
1999        rest1= E;
2000    }
2001    else
2002      divrem (E, bufFactors[k], dummy, rest1, MOD);
2003
2004    buf[k]= mulMod (i.getItem(), rest1, MOD);
2005
2006    if (degree (bufFactors[k], x) > 0)
2007      divrem (buf[k], bufFactors[k] [0], dummy, buf[k], MOD);
2008    else
2009      divrem (buf[k], bufFactors[k], dummy, buf[k], MOD);
2010  }
2011  for (k= 1; k < factors.length(); k++)
2012    bufFactors[k] += xToJ*buf[k];
2013
2014  // update Pi [0]
2015  int degBuf0= degree (bufFactors[0], x);
2016  int degBuf1= degree (bufFactors[1], x);
2017  if (degBuf0 > 0 && degBuf1 > 0)
2018    M (j + 1, 1)= mulMod (bufFactors[0] [j], bufFactors[1] [j], MOD);
2019  CanonicalForm uIZeroJ;
2020  if (j == 1)
2021  {
2022    if (degBuf0 > 0 && degBuf1 > 0)
2023      uIZeroJ= mulMod ((bufFactors[0] [0] + bufFactors[0] [j]),
2024                  (bufFactors[1] [0] + buf[1]), MOD) - M(1, 1) - M(j + 1, 1);
2025    else if (degBuf0 > 0)
2026      uIZeroJ= mulMod (bufFactors[0] [j], bufFactors[1], MOD);
2027    else if (degBuf1 > 0)
2028      uIZeroJ= mulMod (bufFactors[0], buf[1], MOD);
2029    else
2030      uIZeroJ= 0;
2031    Pi [0] += xToJ*uIZeroJ;
2032  }
2033  else
2034  {
2035    if (degBuf0 > 0 && degBuf1 > 0)
2036      uIZeroJ= mulMod ((bufFactors[0] [0] + bufFactors[0] [j]),
2037                  (bufFactors[1] [0] + buf[1]), MOD) - M(1, 1) - M(j + 1, 1);
2038    else if (degBuf0 > 0)
2039      uIZeroJ= mulMod (bufFactors[0] [j], bufFactors[1], MOD);
2040    else if (degBuf1 > 0)
2041      uIZeroJ= mulMod (bufFactors[0], buf[1], MOD);
2042    else
2043      uIZeroJ= 0;
2044    Pi [0] += xToJ*uIZeroJ;
2045  }
2046
2047  CFArray tmp= CFArray (factors.length() - 1);
2048  for (k= 0; k < factors.length() - 1; k++)
2049    tmp[k]= 0;
2050  CFIterator one, two;
2051  one= bufFactors [0];
2052  two= bufFactors [1];
2053  if (degBuf0 > 0 && degBuf1 > 0)
2054  {
2055    for (k= 1; k <= (int) ceil (j/2.0); k++)
2056    {
2057      if (k != j - k + 1)
2058      {
2059        if ((one.hasTerms() && one.exp() == j - k + 1) &&
2060            (two.hasTerms() && two.exp() == j - k + 1))
2061        {
2062          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()),
2063                    (bufFactors[1] [k] + two.coeff()), MOD) - M (k + 1, 1) -
2064                    M (j - k + 2, 1);
2065          one++;
2066          two++;
2067        }
2068        else if (one.hasTerms() && one.exp() == j - k + 1)
2069        {
2070          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()),
2071                    bufFactors[1] [k], MOD) - M (k + 1, 1);
2072          one++;
2073        }
2074        else if (two.hasTerms() && two.exp() == j - k + 1)
2075        {
2076          tmp[0] += mulMod (bufFactors[0] [k], (bufFactors[1] [k] +
2077                    two.coeff()), MOD) - M (k + 1, 1);
2078          two++;
2079        }
2080      }
2081      else
2082      {
2083        tmp[0] += M (k + 1, 1);
2084      }
2085    }
2086  }
2087  Pi [0] += tmp[0]*xToJ*F.mvar();
2088
2089  // update Pi [l]
2090  int degPi, degBuf;
2091  for (int l= 1; l < factors.length() - 1; l++)
2092  {
2093    degPi= degree (Pi [l - 1], x);
2094    degBuf= degree (bufFactors[l + 1], x);
2095    if (degPi > 0 && degBuf > 0)
2096      M (j + 1, l + 1)= mulMod (Pi [l - 1] [j], bufFactors[l + 1] [j], MOD);
2097    if (j == 1)
2098    {
2099      if (degPi > 0 && degBuf > 0)
2100        Pi [l] += xToJ*(mulMod ((Pi [l - 1] [0] + Pi [l - 1] [j]),
2101                  (bufFactors[l + 1] [0] + buf[l + 1]), MOD) - M (j + 1, l +1)-
2102                  M (1, l + 1));
2103      else if (degPi > 0)
2104        Pi [l] += xToJ*(mulMod (Pi [l - 1] [j], bufFactors[l + 1], MOD));
2105      else if (degBuf > 0)
2106        Pi [l] += xToJ*(mulMod (Pi [l - 1], buf[l + 1], MOD));
2107    }
2108    else
2109    {
2110      if (degPi > 0 && degBuf > 0)
2111      {
2112        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
2113        uIZeroJ += mulMod (Pi [l - 1] [0], buf [l + 1], MOD);
2114      }
2115      else if (degPi > 0)
2116        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1], MOD);
2117      else if (degBuf > 0)
2118      {
2119        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
2120        uIZeroJ += mulMod (Pi [l - 1], buf[l + 1], MOD);
2121      }
2122      Pi[l] += xToJ*uIZeroJ;
2123    }
2124    one= bufFactors [l + 1];
2125    two= Pi [l - 1];
2126    if (two.hasTerms() && two.exp() == j + 1)
2127    {
2128      if (degBuf > 0 && degPi > 0)
2129      {
2130          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1][0], MOD);
2131          two++;
2132      }
2133      else if (degPi > 0)
2134      {
2135          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1], MOD);
2136          two++;
2137      }
2138    }
2139    if (degBuf > 0 && degPi > 0)
2140    {
2141      for (k= 1; k <= (int) ceil (j/2.0); k++)
2142      {
2143        if (k != j - k + 1)
2144        {
2145          if ((one.hasTerms() && one.exp() == j - k + 1) &&
2146              (two.hasTerms() && two.exp() == j - k + 1))
2147          {
2148            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()),
2149                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1) -
2150                      M (j - k + 2, l + 1);
2151            one++;
2152            two++;
2153          }
2154          else if (one.hasTerms() && one.exp() == j - k + 1)
2155          {
2156            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()),
2157                      Pi[l - 1] [k], MOD) - M (k + 1, l + 1);
2158            one++;
2159          }
2160          else if (two.hasTerms() && two.exp() == j - k + 1)
2161          {
2162            tmp[l] += mulMod (bufFactors[l + 1] [k],
2163                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1);
2164            two++;
2165          }
2166        }
2167        else
2168          tmp[l] += M (k + 1, l + 1);
2169      }
2170    }
2171    Pi[l] += tmp[l]*xToJ*F.mvar();
2172  }
2173
2174  return;
2175}
2176
2177CFList
2178henselLift23 (const CFList& eval, const CFList& factors, const int* l, CFList&
2179              diophant, CFArray& Pi, CFMatrix& M)
2180{
2181  CFList buf= factors;
2182  int k= 0;
2183  int liftBoundBivar= l[k];
2184  diophant= biDiophantine (eval.getFirst(), buf, liftBoundBivar);
2185  CFList MOD;
2186  MOD.append (power (Variable (2), liftBoundBivar));
2187  CFArray bufFactors= CFArray (factors.length());
2188  k= 0;
2189  CFListIterator j= eval;
2190  j++;
2191  buf.removeFirst();
2192  buf.insert (LC (j.getItem(), 1));
2193  for (CFListIterator i= buf; i.hasItem(); i++, k++)
2194    bufFactors[k]= i.getItem();
2195  Pi= CFArray (factors.length() - 1);
2196  CFListIterator i= buf;
2197  i++;
2198  Variable y= j.getItem().mvar();
2199  Pi [0]= mulMod (i.getItem(), mod (buf.getFirst(), y), MOD);
2200  M (1, 1)= Pi [0];
2201  k= 1;
2202  if (i.hasItem())
2203    i++;
2204  for (; i.hasItem(); i++, k++)
2205  {
2206    Pi [k]= mulMod (Pi [k - 1], i.getItem(), MOD);
2207    M (1, k + 1)= Pi [k];
2208  }
2209
2210  for (int d= 1; d < l[1]; d++)
2211    henselStep (j.getItem(), buf, bufFactors, diophant, M, Pi, d, MOD);
2212  CFList result;
2213  for (k= 1; k < factors.length(); k++)
2214    result.append (bufFactors[k]);
2215  return result;
2216}
2217
2218void
2219henselLiftResume (const CanonicalForm& F, CFList& factors, int start, int end,
2220                  CFArray& Pi, const CFList& diophant, CFMatrix& M,
2221                  const CFList& MOD)
2222{
2223  CFArray bufFactors= CFArray (factors.length());
2224  int i= 0;
2225  CanonicalForm xToStart= power (F.mvar(), start);
2226  for (CFListIterator k= factors; k.hasItem(); k++, i++)
2227  {
2228    if (i == 0)
2229      bufFactors[i]= mod (k.getItem(), xToStart);
2230    else
2231      bufFactors[i]= k.getItem();
2232  }
2233  for (i= start; i < end; i++)
2234    henselStep (F, factors, bufFactors, diophant, M, Pi, i, MOD);
2235
2236  CFListIterator k= factors;
2237  for (i= 0; i < factors.length(); k++, i++)
2238    k.getItem()= bufFactors [i];
2239  factors.removeFirst();
2240  return;
2241}
2242
2243CFList
2244henselLift (const CFList& F, const CFList& factors, const CFList& MOD, CFList&
2245            diophant, CFArray& Pi, CFMatrix& M, const int lOld, const int
2246            lNew)
2247{
2248  diophant= multiRecDiophantine (F.getFirst(), factors, diophant, MOD, lOld);
2249  int k= 0;
2250  CFArray bufFactors= CFArray (factors.length());
2251  for (CFListIterator i= factors; i.hasItem(); i++, k++)
2252  {
2253    if (k == 0)
2254      bufFactors[k]= LC (F.getLast(), 1);
2255    else
2256      bufFactors[k]= i.getItem();
2257  }
2258  CFList buf= factors;
2259  buf.removeFirst();
2260  buf.insert (LC (F.getLast(), 1));
2261  CFListIterator i= buf;
2262  i++;
2263  Variable y= F.getLast().mvar();
2264  Variable x= F.getFirst().mvar();
2265  CanonicalForm xToLOld= power (x, lOld);
2266  Pi [0]= mod (Pi[0], xToLOld);
2267  M (1, 1)= Pi [0];
2268  k= 1;
2269  if (i.hasItem())
2270    i++;
2271  for (; i.hasItem(); i++, k++)
2272  {
2273    Pi [k]= mod (Pi [k], xToLOld);
2274    M (1, k + 1)= Pi [k];
2275  }
2276
2277  for (int d= 1; d < lNew; d++)
2278    henselStep (F.getLast(), buf, bufFactors, diophant, M, Pi, d, MOD);
2279  CFList result;
2280  for (k= 1; k < factors.length(); k++)
2281    result.append (bufFactors[k]);
2282  return result;
2283}
2284
2285CFList
2286henselLift (const CFList& eval, const CFList& factors, const int* l, const int
2287            lLength, bool sort)
2288{
2289  CFList diophant;
2290  CFList buf= factors;
2291  buf.insert (LC (eval.getFirst(), 1));
2292  if (sort)
2293    sortList (buf, Variable (1));
2294  CFArray Pi;
2295  CFMatrix M= CFMatrix (l[1], factors.length());
2296  CFList result= henselLift23 (eval, buf, l, diophant, Pi, M);
2297  if (eval.length() == 2)
2298    return result;
2299  CFList MOD;
2300  for (int i= 0; i < 2; i++)
2301    MOD.append (power (Variable (i + 2), l[i]));
2302  CFListIterator j= eval;
2303  j++;
2304  CFList bufEval;
2305  bufEval.append (j.getItem());
2306  j++;
2307
2308  for (int i= 2; i < lLength && j.hasItem(); i++, j++)
2309  {
2310    result.insert (LC (bufEval.getFirst(), 1));
2311    bufEval.append (j.getItem());
2312    M= CFMatrix (l[i], factors.length());
2313    result= henselLift (bufEval, result, MOD, diophant, Pi, M, l[i - 1], l[i]);
2314    MOD.append (power (Variable (i + 2), l[i]));
2315    bufEval.removeFirst();
2316  }
2317  return result;
2318}
2319
2320void
2321henselStep122 (const CanonicalForm& F, const CFList& factors,
2322              CFArray& bufFactors, const CFList& diophant, CFMatrix& M,
2323              CFArray& Pi, int j, const CFArray& LCs)
2324{
2325  Variable x= F.mvar();
2326  CanonicalForm xToJ= power (x, j);
2327
2328  CanonicalForm E;
2329  // compute the error
2330  if (degree (Pi [factors.length() - 2], x) > 0)
2331    E= F[j] - Pi [factors.length() - 2] [j];
2332  else
2333    E= F[j];
2334
2335  CFArray buf= CFArray (diophant.length());
2336
2337  int k= 0;
2338  CanonicalForm remainder;
2339  // actual lifting
2340  for (CFListIterator i= diophant; i.hasItem(); i++, k++)
2341  {
2342    if (degree (bufFactors[k], x) > 0)
2343      remainder= modNTL (E, bufFactors[k] [0]);
2344    else
2345      remainder= modNTL (E, bufFactors[k]);
2346    buf[k]= mulNTL (i.getItem(), remainder);
2347    if (degree (bufFactors[k], x) > 0)
2348      buf[k]= modNTL (buf[k], bufFactors[k] [0]);
2349    else
2350      buf[k]= modNTL (buf[k], bufFactors[k]);
2351  }
2352
2353  for (k= 0; k < factors.length(); k++)
2354    bufFactors[k] += xToJ*buf[k];
2355
2356  // update Pi [0]
2357  int degBuf0= degree (bufFactors[0], x);
2358  int degBuf1= degree (bufFactors[1], x);
2359  if (degBuf0 > 0 && degBuf1 > 0)
2360  {
2361    M (j + 1, 1)= mulNTL (bufFactors[0] [j], bufFactors[1] [j]);
2362    if (j + 2 <= M.rows())
2363      M (j + 2, 1)= mulNTL (bufFactors[0] [j + 1], bufFactors[1] [j + 1]);
2364  }
2365  CanonicalForm uIZeroJ;
2366  if (degBuf0 > 0 && degBuf1 > 0)
2367    uIZeroJ= mulNTL(bufFactors[0][0],buf[1])+mulNTL (bufFactors[1][0], buf[0]);
2368  else if (degBuf0 > 0)
2369    uIZeroJ= mulNTL (buf[0], bufFactors[1]);
2370  else if (degBuf1 > 0)
2371    uIZeroJ= mulNTL (bufFactors[0], buf [1]);
2372  else
2373    uIZeroJ= 0;
2374  Pi [0] += xToJ*uIZeroJ;
2375
2376  CFArray tmp= CFArray (factors.length() - 1);
2377  for (k= 0; k < factors.length() - 1; k++)
2378    tmp[k]= 0;
2379  CFIterator one, two;
2380  one= bufFactors [0];
2381  two= bufFactors [1];
2382  if (degBuf0 > 0 && degBuf1 > 0)
2383  {
2384    while (one.hasTerms() && one.exp() > j) one++;
2385    while (two.hasTerms() && two.exp() > j) two++;
2386    for (k= 1; k <= (int) ceil (j/2.0); k++)
2387    {
2388      if (one.hasTerms() && two.hasTerms())
2389      {
2390        if (k != j - k + 1)
2391        {
2392          if ((one.hasTerms() && one.exp() == j - k + 1) && +
2393              (two.hasTerms() && two.exp() == j - k + 1))
2394        {
2395          tmp[0] += mulNTL ((bufFactors[0][k]+one.coeff()),(bufFactors[1][k] +
2396                      two.coeff())) - M (k + 1, 1) - M (j - k + 2, 1);
2397          one++;
2398          two++;
2399        }
2400        else if (one.hasTerms() && one.exp() == j - k + 1)
2401        {
2402          tmp[0] += mulNTL ((bufFactors[0][k]+one.coeff()), bufFactors[1] [k]) -
2403                      M (k + 1, 1);
2404          one++;
2405        }
2406        else if (two.hasTerms() && two.exp() == j - k + 1)
2407        {
2408          tmp[0] += mulNTL (bufFactors[0][k],(bufFactors[1][k] + two.coeff())) -
2409                    M (k + 1, 1);
2410          two++;
2411        }
2412      }
2413      else
2414        tmp[0] += M (k + 1, 1);
2415      }
2416    }
2417  }
2418
2419  if (degBuf0 >= j + 1 && degBuf1 >= j + 1)
2420  {
2421    if (j + 2 <= M.rows())
2422      tmp [0] += mulNTL ((bufFactors [0] [j + 1]+ bufFactors [0] [0]),
2423                         (bufFactors [1] [j + 1] + bufFactors [1] [0]))
2424                         - M(1,1) - M (j + 2,1);
2425  }
2426  else if (degBuf0 >= j + 1)
2427  {
2428    if (degBuf1 > 0)
2429      tmp[0] += mulNTL (bufFactors [0] [j+1], bufFactors [1] [0]);
2430    else
2431      tmp[0] += mulNTL (bufFactors [0] [j+1], bufFactors [1]);
2432  }
2433  else if (degBuf1 >= j + 1)
2434  {
2435    if (degBuf0 > 0)
2436      tmp[0] += mulNTL (bufFactors [0] [0], bufFactors [1] [j + 1]);
2437    else
2438      tmp[0] += mulNTL (bufFactors [0], bufFactors [1] [j + 1]);
2439  }
2440
2441  Pi [0] += tmp[0]*xToJ*F.mvar();
2442  return;
2443}
2444
2445void
2446henselLift122 (const CanonicalForm& F, CFList& factors, int l, CFArray& Pi,
2447              CFList& diophant, CFMatrix& M, const CFArray& LCs, bool sort)
2448{
2449  if (sort)
2450    sortList (factors, Variable (1));
2451  Pi= CFArray (factors.length() - 2);
2452  CFList bufFactors2= factors;
2453  bufFactors2.removeFirst();
2454  diophant.removeFirst();
2455  CFListIterator iter= diophant;
2456  CanonicalForm s,t;
2457  extgcd (bufFactors2.getFirst(), bufFactors2.getLast(), s, t);
2458  diophant= CFList();
2459  diophant.append (t);
2460  diophant.append (s);
2461  DEBOUTLN (cerr, "diophant= " << diophant);
2462
2463  CFArray bufFactors= CFArray (bufFactors2.length());
2464  int i= 0;
2465  for (CFListIterator k= bufFactors2; k.hasItem(); i++, k++)
2466    bufFactors[i]= replaceLc (k.getItem(), LCs [i]);
2467
2468  Variable x= F.mvar();
2469  if (degree (bufFactors[0], x) > 0 && degree (bufFactors [1], x) > 0)
2470  {
2471    M (1, 1)= mulNTL (bufFactors [0] [0], bufFactors[1] [0]);
2472    Pi [0]= M (1, 1) + (mulNTL (bufFactors [0] [1], bufFactors[1] [0]) +
2473                        mulNTL (bufFactors [0] [0], bufFactors [1] [1]))*x;
2474  }
2475  else if (degree (bufFactors[0], x) > 0)
2476  {
2477    M (1, 1)= mulNTL (bufFactors [0] [0], bufFactors[1]);
2478    Pi [0]= M (1, 1) +
2479            mulNTL (bufFactors [0] [1], bufFactors[1])*x;
2480  }
2481  else if (degree (bufFactors[1], x) > 0)
2482  {
2483    M (1, 1)= mulNTL (bufFactors [0], bufFactors[1] [0]);
2484    Pi [0]= M (1, 1) +
2485            mulNTL (bufFactors [0], bufFactors[1] [1])*x;
2486  }
2487  else
2488  {
2489    M (1, 1)= mulNTL (bufFactors [0], bufFactors[1]);
2490    Pi [0]= M (1, 1);
2491  }
2492
2493  for (i= 1; i < l; i++)
2494    henselStep122 (F, bufFactors2, bufFactors, diophant, M, Pi, i, LCs);
2495
2496  factors= CFList();
2497  for (i= 0; i < bufFactors.size(); i++)
2498    factors.append (bufFactors[i]);
2499  return;
2500}
2501
2502/// solve \f$ E=sum_{i= 1}^{r}{\sigma_{i}prod_{j=1, j\neq i}^{r}{f_{i}}}\f$
2503/// mod M, products contains \f$ prod_{j=1, j\neq i}^{r}{f_{i}}} \f$
2504static inline
2505CFList
2506diophantine (const CFList& recResult, const CFList& factors,
2507             const CFList& products, const CFList& M, const CanonicalForm& E,
2508             bool& bad)
2509{
2510  if (M.isEmpty())
2511  {
2512    CFList result;
2513    CFListIterator j= factors;
2514    CanonicalForm buf;
2515    for (CFListIterator i= recResult; i.hasItem(); i++, j++)
2516    {
2517      ASSERT (E.isUnivariate() || E.inCoeffDomain(),
2518              "constant or univariate poly expected");
2519      ASSERT (i.getItem().isUnivariate() || i.getItem().inCoeffDomain(),
2520              "constant or univariate poly expected");
2521      ASSERT (j.getItem().isUnivariate() || j.getItem().inCoeffDomain(),
2522              "constant or univariate poly expected");
2523      buf= mulNTL (E, i.getItem());
2524      result.append (modNTL (buf, j.getItem()));
2525    }
2526    return result;
2527  }
2528  Variable y= M.getLast().mvar();
2529  CFList bufFactors= factors;
2530  for (CFListIterator i= bufFactors; i.hasItem(); i++)
2531    i.getItem()= mod (i.getItem(), y);
2532  CFList bufProducts= products;
2533  for (CFListIterator i= bufProducts; i.hasItem(); i++)
2534    i.getItem()= mod (i.getItem(), y);
2535  CFList buf= M;
2536  buf.removeLast();
2537  CanonicalForm bufE= mod (E, y);
2538  CFList recDiophantine= diophantine (recResult, bufFactors, bufProducts, buf,
2539                                      bufE, bad);
2540
2541  if (bad)
2542    return CFList();
2543
2544  CanonicalForm e= E;
2545  CFListIterator j= products;
2546  for (CFListIterator i= recDiophantine; i.hasItem(); i++, j++)
2547    e -= i.getItem()*j.getItem();
2548
2549  CFList result= recDiophantine;
2550  int d= degree (M.getLast());
2551  CanonicalForm coeffE;
2552  for (int i= 1; i < d; i++)
2553  {
2554    if (degree (e, y) > 0)
2555      coeffE= e[i];
2556    else
2557      coeffE= 0;
2558    if (!coeffE.isZero())
2559    {
2560      CFListIterator k= result;
2561      recDiophantine= diophantine (recResult, bufFactors, bufProducts, buf,
2562                                   coeffE, bad);
2563      if (bad)
2564        return CFList();
2565      CFListIterator l= products;
2566      for (j= recDiophantine; j.hasItem(); j++, k++, l++)
2567      {
2568        k.getItem() += j.getItem()*power (y, i);
2569        e -= j.getItem()*power (y, i)*l.getItem();
2570      }
2571    }
2572    if (e.isZero())
2573      break;
2574  }
2575  if (!e.isZero())
2576  {
2577    bad= true;
2578    return CFList();
2579  }
2580  return result;
2581}
2582
2583static inline
2584void
2585henselStep2 (const CanonicalForm& F, const CFList& factors, CFArray& bufFactors,
2586            const CFList& diophant, CFMatrix& M, CFArray& Pi,
2587            const CFList& products, int j, const CFList& MOD, bool& noOneToOne)
2588{
2589  CanonicalForm E;
2590  CanonicalForm xToJ= power (F.mvar(), j);
2591  Variable x= F.mvar();
2592
2593  // compute the error
2594#ifdef DEBUGOUTPUT
2595    CanonicalForm test= 1;
2596    for (int i= 0; i < factors.length(); i++)
2597    {
2598      if (i == 0)
2599        test *= mod (bufFactors [i], power (x, j));
2600      else
2601        test *= bufFactors[i];
2602    }
2603    test= mod (test, power (x, j));
2604    test= mod (test, MOD);
2605    CanonicalForm test2= mod (F, power (x, j - 1)) - mod (test, power (x, j-1));
2606    DEBOUTLN (cerr, "test= " << test2);
2607#endif
2608
2609  if (degree (Pi [factors.length() - 2], x) > 0)
2610    E= F[j] - Pi [factors.length() - 2] [j];
2611  else
2612    E= F[j];
2613
2614  CFArray buf= CFArray (diophant.length());
2615
2616  // actual lifting
2617  CFList diophantine2= diophantine (diophant, factors, products, MOD, E,
2618                                    noOneToOne);
2619
2620  if (noOneToOne)
2621    return;
2622
2623  int k= 0;
2624  for (CFListIterator i= diophantine2; k < factors.length(); k++, i++)
2625  {
2626    buf[k]= i.getItem();
2627    bufFactors[k] += xToJ*i.getItem();
2628  }
2629
2630  // update Pi [0]
2631  int degBuf0= degree (bufFactors[0], x);
2632  int degBuf1= degree (bufFactors[1], x);
2633  if (degBuf0 > 0 && degBuf1 > 0)
2634  {
2635    M (j + 1, 1)= mulMod (bufFactors[0] [j], bufFactors[1] [j], MOD);
2636    if (j + 2 <= M.rows())
2637      M (j + 2, 1)= mulMod (bufFactors[0] [j + 1], bufFactors[1] [j + 1], MOD);
2638  }
2639  CanonicalForm uIZeroJ;
2640
2641  if (degBuf0 > 0 && degBuf1 > 0)
2642    uIZeroJ= mulMod (bufFactors[0] [0], buf[1], MOD) +
2643             mulMod (bufFactors[1] [0], buf[0], MOD);
2644  else if (degBuf0 > 0)
2645    uIZeroJ= mulMod (buf[0], bufFactors[1], MOD);
2646  else if (degBuf1 > 0)
2647    uIZeroJ= mulMod (bufFactors[0], buf[1], MOD);
2648  else
2649    uIZeroJ= 0;
2650  Pi [0] += xToJ*uIZeroJ;
2651
2652  CFArray tmp= CFArray (factors.length() - 1);
2653  for (k= 0; k < factors.length() - 1; k++)
2654    tmp[k]= 0;
2655  CFIterator one, two;
2656  one= bufFactors [0];
2657  two= bufFactors [1];
2658  if (degBuf0 > 0 && degBuf1 > 0)
2659  {
2660    while (one.hasTerms() && one.exp() > j) one++;
2661    while (two.hasTerms() && two.exp() > j) two++;
2662    for (k= 1; k <= (int) ceil (j/2.0); k++)
2663    {
2664      if (k != j - k + 1)
2665      {
2666        if ((one.hasTerms() && one.exp() == j - k + 1) &&
2667            (two.hasTerms() && two.exp() == j - k + 1))
2668        {
2669          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()),
2670                    (bufFactors[1] [k] + two.coeff()), MOD) - M (k + 1, 1) -
2671                    M (j - k + 2, 1);
2672          one++;
2673          two++;
2674        }
2675        else if (one.hasTerms() && one.exp() == j - k + 1)
2676        {
2677          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()),
2678                    bufFactors[1] [k], MOD) - M (k + 1, 1);
2679          one++;
2680        }
2681        else if (two.hasTerms() && two.exp() == j - k + 1)
2682        {
2683          tmp[0] += mulMod (bufFactors[0] [k], (bufFactors[1] [k] +
2684                    two.coeff()), MOD) - M (k + 1, 1);
2685          two++;
2686        }
2687      }
2688      else
2689      {
2690        tmp[0] += M (k + 1, 1);
2691      }
2692    }
2693  }
2694
2695  if (degBuf0 >= j + 1 && degBuf1 >= j + 1)
2696  {
2697    if (j + 2 <= M.rows())
2698      tmp [0] += mulMod ((bufFactors [0] [j + 1]+ bufFactors [0] [0]),
2699                         (bufFactors [1] [j + 1] + bufFactors [1] [0]), MOD)
2700                         - M(1,1) - M (j + 2,1);
2701  }
2702  else if (degBuf0 >= j + 1)
2703  {
2704    if (degBuf1 > 0)
2705      tmp[0] += mulMod (bufFactors [0] [j+1], bufFactors [1] [0], MOD);
2706    else
2707      tmp[0] += mulMod (bufFactors [0] [j+1], bufFactors [1], MOD);
2708  }
2709  else if (degBuf1 >= j + 1)
2710  {
2711    if (degBuf0 > 0)
2712      tmp[0] += mulMod (bufFactors [0] [0], bufFactors [1] [j + 1], MOD);
2713    else
2714      tmp[0] += mulMod (bufFactors [0], bufFactors [1] [j + 1], MOD);
2715  }
2716  Pi [0] += tmp[0]*xToJ*F.mvar();
2717
2718  // update Pi [l]
2719  int degPi, degBuf;
2720  for (int l= 1; l < factors.length() - 1; l++)
2721  {
2722    degPi= degree (Pi [l - 1], x);
2723    degBuf= degree (bufFactors[l + 1], x);
2724    if (degPi > 0 && degBuf > 0)
2725    {
2726      M (j + 1, l + 1)= mulMod (Pi [l - 1] [j], bufFactors[l + 1] [j], MOD);
2727      if (j + 2 <= M.rows())
2728        M (j + 2, l + 1)= mulMod (Pi [l - 1] [j + 1], bufFactors[l + 1] [j + 1],
2729                                  MOD);
2730    }
2731
2732    if (degPi > 0 && degBuf > 0)
2733      uIZeroJ= mulMod (Pi[l -1] [0], buf[l + 1], MOD) +
2734               mulMod (uIZeroJ, bufFactors[l+1] [0], MOD);
2735    else if (degPi > 0)
2736      uIZeroJ= mulMod (uIZeroJ, bufFactors[l + 1], MOD);
2737    else if (degBuf > 0)
2738      uIZeroJ= mulMod (Pi[l - 1], buf[1], MOD);
2739    else
2740      uIZeroJ= 0;
2741
2742    Pi [l] += xToJ*uIZeroJ;
2743
2744    one= bufFactors [l + 1];
2745    two= Pi [l - 1];
2746    if (degBuf > 0 && degPi > 0)
2747    {
2748      while (one.hasTerms() && one.exp() > j) one++;
2749      while (two.hasTerms() && two.exp() > j) two++;
2750      for (k= 1; k <= (int) ceil (j/2.0); k++)
2751      {
2752        if (k != j - k + 1)
2753        {
2754          if ((one.hasTerms() && one.exp() == j - k + 1) &&
2755              (two.hasTerms() && two.exp() == j - k + 1))
2756          {
2757            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()),
2758                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1) -
2759                      M (j - k + 2, l + 1);
2760            one++;
2761            two++;
2762          }
2763          else if (one.hasTerms() && one.exp() == j - k + 1)
2764          {
2765            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()),
2766                      Pi[l - 1] [k], MOD) - M (k + 1, l + 1);
2767            one++;
2768          }
2769          else if (two.hasTerms() && two.exp() == j - k + 1)
2770          {
2771            tmp[l] += mulMod (bufFactors[l + 1] [k],
2772                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1);
2773            two++;
2774           }
2775        }
2776        else
2777          tmp[l] += M (k + 1, l + 1);
2778      }
2779    }
2780
2781    if (degPi >= j + 1 && degBuf >= j + 1)
2782    {
2783      if (j + 2 <= M.rows())
2784        tmp [l] += mulMod ((Pi [l - 1] [j + 1]+ Pi [l - 1] [0]),
2785                           (bufFactors [l + 1] [j + 1] + bufFactors [l + 1] [0])
2786                            , MOD) - M(1,l+1) - M (j + 2,l+1);
2787    }
2788    else if (degPi >= j + 1)
2789    {
2790      if (degBuf > 0)
2791        tmp[l] += mulMod (Pi [l - 1] [j+1], bufFactors [l + 1] [0], MOD);
2792      else
2793        tmp[l] += mulMod (Pi [l - 1] [j+1], bufFactors [l + 1], MOD);
2794    }
2795    else if (degBuf >= j + 1)
2796    {
2797      if (degPi > 0)
2798        tmp[l] += mulMod (Pi [l - 1] [0], bufFactors [l + 1] [j + 1], MOD);
2799      else
2800        tmp[l] += mulMod (Pi [l - 1], bufFactors [l + 1] [j + 1], MOD);
2801    }
2802
2803    Pi[l] += tmp[l]*xToJ*F.mvar();
2804  }
2805  return;
2806}
2807
2808// wrt. Variable (1)
2809CanonicalForm replaceLC (const CanonicalForm& F, const CanonicalForm& c)
2810{
2811  if (degree (F, 1) <= 0)
2812   return c;
2813  else
2814  {
2815    CanonicalForm result= swapvar (F, Variable (F.level() + 1), Variable (1));
2816    result += (swapvar (c, Variable (F.level() + 1), Variable (1))
2817              - LC (result))*power (result.mvar(), degree (result));
2818    return swapvar (result, Variable (F.level() + 1), Variable (1));
2819  }
2820}
2821
2822CFList
2823henselLift232 (const CFList& eval, const CFList& factors, int* l, CFList&
2824              diophant, CFArray& Pi, CFMatrix& M, const CFList& LCs1,
2825              const CFList& LCs2, bool& bad)
2826{
2827  CFList buf= factors;
2828  int k= 0;
2829  int liftBoundBivar= l[k];
2830  CFList bufbuf= factors;
2831  Variable v= Variable (2);
2832
2833  CFList MOD;
2834  MOD.append (power (Variable (2), liftBoundBivar));
2835  CFArray bufFactors= CFArray (factors.length());
2836  k= 0;
2837  CFListIterator j= eval;
2838  j++;
2839  CFListIterator iter1= LCs1;
2840  CFListIterator iter2= LCs2;
2841  iter1++;
2842  iter2++;
2843  bufFactors[0]= replaceLC (buf.getFirst(), iter1.getItem());
2844  bufFactors[1]= replaceLC (buf.getLast(), iter2.getItem());
2845
2846  CFListIterator i= buf;
2847  i++;
2848  Variable y= j.getItem().mvar();
2849  if (y.level() != 3)
2850    y= Variable (3);
2851
2852  Pi[0]= mod (Pi[0], power (v, liftBoundBivar));
2853  M (1, 1)= Pi[0];
2854  if (degree (bufFactors[0], y) > 0 && degree (bufFactors [1], y) > 0)
2855    Pi [0] += (mulMod (bufFactors [0] [1], bufFactors[1] [0], MOD) +
2856                        mulMod (bufFactors [0] [0], bufFactors [1] [1], MOD))*y;
2857  else if (degree (bufFactors[0], y) > 0)
2858    Pi [0] += mulMod (bufFactors [0] [1], bufFactors[1], MOD)*y;
2859  else if (degree (bufFactors[1], y) > 0)
2860    Pi [0] += mulMod (bufFactors [0], bufFactors[1] [1], MOD)*y;
2861
2862  CFList products;
2863  for (int i= 0; i < bufFactors.size(); i++)
2864  {
2865    if (degree (bufFactors[i], y) > 0)
2866      products.append (eval.getFirst()/bufFactors[i] [0]);
2867    else
2868      products.append (eval.getFirst()/bufFactors[i]);
2869  }
2870
2871  for (int d= 1; d < l[1]; d++)
2872  {
2873    henselStep2 (j.getItem(), buf, bufFactors, diophant, M, Pi, products, d, MOD, bad);
2874    if (bad)
2875      return CFList();
2876  }
2877  CFList result;
2878  for (k= 0; k < factors.length(); k++)
2879    result.append (bufFactors[k]);
2880  return result;
2881}
2882
2883
2884CFList
2885henselLift2 (const CFList& F, const CFList& factors, const CFList& MOD, CFList&
2886            diophant, CFArray& Pi, CFMatrix& M, const int lOld, int&
2887            lNew, const CFList& LCs1, const CFList& LCs2, bool& bad)
2888{
2889  int k= 0;
2890  CFArray bufFactors= CFArray (factors.length());
2891  bufFactors[0]= replaceLC (factors.getFirst(), LCs1.getLast());
2892  bufFactors[1]= replaceLC (factors.getLast(), LCs2.getLast());
2893  CFList buf= factors;
2894  Variable y= F.getLast().mvar();
2895  Variable x= F.getFirst().mvar();
2896  CanonicalForm xToLOld= power (x, lOld);
2897  Pi [0]= mod (Pi[0], xToLOld);
2898  M (1, 1)= Pi [0];
2899
2900  if (degree (bufFactors[0], y) > 0 && degree (bufFactors [1], y) > 0)
2901    Pi [0] += (mulMod (bufFactors [0] [1], bufFactors[1] [0], MOD) +
2902                        mulMod (bufFactors [0] [0], bufFactors [1] [1], MOD))*y;
2903  else if (degree (bufFactors[0], y) > 0)
2904    Pi [0] += mulMod (bufFactors [0] [1], bufFactors[1], MOD)*y;
2905  else if (degree (bufFactors[1], y) > 0)
2906    Pi [0] += mulMod (bufFactors [0], bufFactors[1] [1], MOD)*y;
2907
2908  CFList products;
2909  for (int i= 0; i < bufFactors.size(); i++)
2910  {
2911    if (degree (bufFactors[i], y) > 0)
2912    {
2913      if (!fdivides (bufFactors[i] [0], F.getFirst()))
2914      {
2915        bad= true;
2916        return CFList();
2917      }
2918      products.append (F.getFirst()/bufFactors[i] [0]);
2919    }
2920    else
2921    {
2922      if (!fdivides (bufFactors[i], F.getFirst()))
2923      {
2924        bad= true;
2925        return CFList();
2926      }
2927      products.append (F.getFirst()/bufFactors[i]);
2928    }
2929  }
2930
2931  for (int d= 1; d < lNew; d++)
2932  {
2933    henselStep2 (F.getLast(), buf, bufFactors, diophant, M, Pi, products, d, MOD, bad);
2934    if (bad)
2935      return CFList();
2936  }
2937
2938  CFList result;
2939  for (k= 0; k < factors.length(); k++)
2940    result.append (bufFactors[k]);
2941  return result;
2942}
2943
2944CFList
2945henselLift2 (const CFList& eval, const CFList& factors, int* l, const int
2946             lLength, bool sort, const CFList& LCs1, const CFList& LCs2,
2947             const CFArray& Pi, const CFList& diophant, bool& bad)
2948{
2949  CFList bufDiophant= diophant;
2950  CFList buf= factors;
2951  if (sort)
2952    sortList (buf, Variable (1));
2953  CFArray bufPi= Pi;
2954  CFMatrix M= CFMatrix (l[1], factors.length());
2955  CFList result= henselLift232(eval, buf, l, bufDiophant, bufPi, M, LCs1, LCs2,
2956                               bad);
2957  if (bad)
2958    return CFList();
2959
2960  if (eval.length() == 2)
2961    return result;
2962  CFList MOD;
2963  for (int i= 0; i < 2; i++)
2964    MOD.append (power (Variable (i + 2), l[i]));
2965  CFListIterator j= eval;
2966  j++;
2967  CFList bufEval;
2968  bufEval.append (j.getItem());
2969  j++;
2970  CFListIterator jj= LCs1;
2971  CFListIterator jjj= LCs2;
2972  CFList bufLCs1, bufLCs2;
2973  jj++, jjj++;
2974  bufLCs1.append (jj.getItem());
2975  bufLCs2.append (jjj.getItem());
2976  jj++, jjj++;
2977
2978  for (int i= 2; i < lLength && j.hasItem(); i++, j++, jj++, jjj++)
2979  {
2980    bufEval.append (j.getItem());
2981    bufLCs1.append (jj.getItem());
2982    bufLCs2.append (jjj.getItem());
2983    M= CFMatrix (l[i], factors.length());
2984    result= henselLift2 (bufEval, result, MOD, bufDiophant, bufPi, M, l[i - 1],
2985                         l[i], bufLCs1, bufLCs2, bad);
2986    if (bad)
2987      return CFList();
2988    MOD.append (power (Variable (i + 2), l[i]));
2989    bufEval.removeFirst();
2990    bufLCs1.removeFirst();
2991    bufLCs2.removeFirst();
2992  }
2993  return result;
2994}
2995
2996CFList
2997nonMonicHenselLift23 (const CanonicalForm& F, const CFList& factors, const
2998                      CFList& LCs, CFList& diophant, CFArray& Pi, int liftBound,
2999                      int bivarLiftBound, bool& bad)
3000{
3001  CFList bufFactors2= factors;
3002
3003  Variable y= Variable (2);
3004  for (CFListIterator i= bufFactors2; i.hasItem(); i++)
3005    i.getItem()= mod (i.getItem(), y);
3006
3007  CanonicalForm bufF= F;
3008  bufF= mod (bufF, y);
3009  bufF= mod (bufF, Variable (3));
3010
3011  diophant= diophantine (bufF, bufFactors2);
3012
3013  CFMatrix M= CFMatrix (liftBound, bufFactors2.length() - 1);
3014
3015  Pi= CFArray (bufFactors2.length() - 1);
3016
3017  CFArray bufFactors= CFArray (bufFactors2.length());
3018  CFListIterator j= LCs;
3019  int i= 0;
3020  for (CFListIterator k= factors; k.hasItem(); j++, k++, i++)
3021    bufFactors[i]= replaceLC (k.getItem(), j.getItem());
3022
3023  //initialise Pi
3024  Variable v= Variable (3);
3025  CanonicalForm yToL= power (y, bivarLiftBound);
3026  if (degree (bufFactors[0], v) > 0 && degree (bufFactors [1], v) > 0)
3027  {
3028    M (1, 1)= mulMod2 (bufFactors [0] [0], bufFactors[1] [0], yToL);
3029    Pi [0]= M (1,1) + (mulMod2 (bufFactors [0] [1], bufFactors[1] [0], yToL) +
3030                       mulMod2 (bufFactors [0] [0], bufFactors [1] [1], yToL))*v;
3031  }
3032  else if (degree (bufFactors[0], v) > 0)
3033  {
3034    M (1,1)= mulMod2 (bufFactors [0] [0], bufFactors [1], yToL);
3035    Pi [0]=  M(1,1) + mulMod2 (bufFactors [0] [1], bufFactors[1], yToL)*v;
3036  }
3037  else if (degree (bufFactors[1], v) > 0)
3038  {
3039    M (1,1)= mulMod2 (bufFactors [0], bufFactors [1] [0], yToL);
3040    Pi [0]= M (1,1) + mulMod2 (bufFactors [0], bufFactors[1] [1], yToL)*v;
3041  }
3042  else
3043  {
3044    M (1,1)= mulMod2 (bufFactors [0], bufFactors [1], yToL);
3045    Pi [0]= M (1,1);
3046  }
3047
3048  for (i= 1; i < Pi.size(); i++)
3049  {
3050    if (degree (Pi[i-1], v) > 0 && degree (bufFactors [i+1], v) > 0)
3051    {
3052      M (1,i+1)= mulMod2 (Pi[i-1] [0], bufFactors[i+1] [0], yToL);
3053      Pi [i]= M (1,i+1) + (mulMod2 (Pi[i-1] [1], bufFactors[i+1] [0], yToL) +
3054                       mulMod2 (Pi[i-1] [0], bufFactors [i+1] [1], yToL))*v;
3055    }
3056    else if (degree (Pi[i-1], v) > 0)
3057    {
3058      M (1,i+1)= mulMod2 (Pi[i-1] [0], bufFactors [i+1], yToL);
3059      Pi [i]=  M(1,i+1) + mulMod2 (Pi[i-1] [1], bufFactors[i+1], yToL)*v;
3060    }
3061    else if (degree (bufFactors[i+1], v) > 0)
3062    {
3063      M (1,i+1)= mulMod2 (Pi[i-1], bufFactors [i+1] [0], yToL);
3064      Pi [i]= M (1,i+1) + mulMod2 (Pi[i-1], bufFactors[i+1] [1], yToL)*v;
3065    }
3066    else
3067    {
3068      M (1,i+1)= mulMod2 (Pi [i-1], bufFactors [i+1], yToL);
3069      Pi [i]= M (1,i+1);
3070    }
3071  }
3072
3073  CFList products;
3074  bufF= mod (F, Variable (3));
3075  for (CFListIterator k= factors; k.hasItem(); k++)
3076    products.append (bufF/k.getItem());
3077
3078  CFList MOD= CFList (power (v, liftBound));
3079  MOD.insert (yToL);
3080  for (int d= 1; d < liftBound; d++)
3081  {
3082    henselStep2 (F, factors, bufFactors, diophant, M, Pi, products, d, MOD, bad);
3083    if (bad)
3084      return CFList();
3085  }
3086
3087  CFList result;
3088  for (i= 0; i < factors.length(); i++)
3089    result.append (bufFactors[i]);
3090  return result;
3091}
3092
3093CFList
3094nonMonicHenselLift (const CFList& F, const CFList& factors, const CFList& LCs,
3095                    CFList& diophant, CFArray& Pi, CFMatrix& M, const int lOld,
3096                    int& lNew, const CFList& MOD, bool& noOneToOne
3097                   )
3098{
3099
3100  int k= 0;
3101  CFArray bufFactors= CFArray (factors.length());
3102  CFListIterator j= LCs;
3103  for (CFListIterator i= factors; i.hasItem(); i++, j++, k++)
3104    bufFactors [k]= replaceLC (i.getItem(), j.getItem());
3105
3106  Variable y= F.getLast().mvar();
3107  Variable x= F.getFirst().mvar();
3108  CanonicalForm xToLOld= power (x, lOld);
3109
3110  Pi [0]= mod (Pi[0], xToLOld);
3111  M (1, 1)= Pi [0];
3112
3113  if (degree (bufFactors[0], y) > 0 && degree (bufFactors [1], y) > 0)
3114    Pi [0] += (mulMod (bufFactors [0] [1], bufFactors[1] [0], MOD) +
3115                        mulMod (bufFactors [0] [0], bufFactors [1] [1], MOD))*y;
3116  else if (degree (bufFactors[0], y) > 0)
3117    Pi [0] += mulMod (bufFactors [0] [1], bufFactors[1], MOD)*y;
3118  else if (degree (bufFactors[1], y) > 0)
3119    Pi [0] += mulMod (bufFactors [0], bufFactors[1] [1], MOD)*y;
3120
3121  for (int i= 1; i < Pi.size(); i++)
3122  {
3123    Pi [i]= mod (Pi [i], xToLOld);
3124    M (1, i + 1)= Pi [i];
3125
3126    if (degree (Pi[i-1], y) > 0 && degree (bufFactors [i+1], y) > 0)
3127      Pi [i] += (mulMod (Pi[i-1] [1], bufFactors[i+1] [0], MOD) +
3128                 mulMod (Pi[i-1] [0], bufFactors [i+1] [1], MOD))*y;
3129    else if (degree (Pi[i-1], y) > 0)
3130      Pi [i] += mulMod (Pi[i-1] [1], bufFactors[i+1], MOD)*y;
3131    else if (degree (bufFactors[i+1], y) > 0)
3132      Pi [i] += mulMod (Pi[i-1], bufFactors[i+1] [1], MOD)*y;
3133  }
3134
3135  CFList products;
3136  CanonicalForm bufF= F.getFirst();
3137
3138  for (int i= 0; i < bufFactors.size(); i++)
3139  {
3140    if (degree (bufFactors[i], y) > 0)
3141    {
3142      if (!fdivides (bufFactors[i] [0], bufF))
3143      {
3144        noOneToOne= true;
3145        return factors;
3146      }
3147      products.append (bufF/bufFactors[i] [0]);
3148    }
3149    else
3150    {
3151      if (!fdivides (bufFactors[i], bufF))
3152      {
3153        noOneToOne= true;
3154        return factors;
3155      }
3156      products.append (bufF/bufFactors[i]);
3157    }
3158  }
3159
3160  for (int d= 1; d < lNew; d++)
3161  {
3162    henselStep2 (F.getLast(), factors, bufFactors, diophant, M, Pi, products, d,
3163                 MOD, noOneToOne);
3164    if (noOneToOne)
3165      return CFList();
3166  }
3167
3168  CFList result;
3169  for (k= 0; k < factors.length(); k++)
3170    result.append (bufFactors[k]);
3171  return result;
3172}
3173
3174CFList
3175nonMonicHenselLift (const CFList& eval, const CFList& factors,
3176                    CFList* const& LCs, CFList& diophant, CFArray& Pi,
3177                    int* liftBound, int length, bool& noOneToOne
3178                   )
3179{
3180  CFList bufDiophant= diophant;
3181  CFList buf= factors;
3182  CFArray bufPi= Pi;
3183  CFMatrix M= CFMatrix (liftBound[1], factors.length() - 1);
3184  int k= 0;
3185
3186  CFList result=
3187  nonMonicHenselLift23 (eval.getFirst(), factors, LCs [0], diophant, bufPi,
3188                        liftBound[1], liftBound[0], noOneToOne);
3189
3190  if (noOneToOne)
3191    return CFList();
3192
3193  if (eval.length() == 1)
3194    return result;
3195
3196  k++;
3197  CFList MOD;
3198  for (int i= 0; i < 2; i++)
3199    MOD.append (power (Variable (i + 2), liftBound[i]));
3200
3201  CFListIterator j= eval;
3202  CFList bufEval;
3203  bufEval.append (j.getItem());
3204  j++;
3205
3206  for (int i= 2; i <= length && j.hasItem(); i++, j++, k++)
3207  {
3208    bufEval.append (j.getItem());
3209    M= CFMatrix (liftBound[i], factors.length() - 1);
3210    result= nonMonicHenselLift (bufEval, result, LCs [i-1], diophant, bufPi, M,
3211                                liftBound[i-1], liftBound[i], MOD, noOneToOne);
3212    if (noOneToOne)
3213      return result;
3214    MOD.append (power (Variable (i + 2), liftBound[i]));
3215    bufEval.removeFirst();
3216  }
3217
3218  return result;
3219}
3220
3221#endif
3222/* HAVE_NTL */
3223
Note: See TracBrowser for help on using the repository browser.