source: git/factory/facHensel.cc @ dd2a9b3

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