source: git/factory/facHensel.cc @ 7b8a416

spielwiese
Last change on this file since 7b8a416 was 018577, checked in by Martin Lee <martinlee84@…>, 14 years ago
new sparse modular gcd over finite fields, new EZ gcd over finite fields, which is now switched on by default git-svn-id: file:///usr/local/Singular/svn/trunk@13185 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 61.6 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 replaceLC (const CanonicalForm& F, const CanonicalForm& c);
36
37static inline
38CanonicalForm
39mulNTL (const CanonicalForm& F, const CanonicalForm& G)
40{
41  if (F.inCoeffDomain() || G.inCoeffDomain())
42    return F*G;
43  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
44  ASSERT (F.level() == G.level(), "expected polys of same level");
45  if (CFFactory::gettype() == GaloisFieldDomain)
46    return F*G;
47  zz_p::init (getCharacteristic());
48  Variable alpha;
49  CanonicalForm result;
50  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
51  {
52    zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (alpha));
53    zz_pE::init (NTLMipo);
54    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
55    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
56    mul (NTLF, NTLF, NTLG);
57    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
58  }
59  else
60  {
61    zz_pX NTLF= convertFacCF2NTLzzpX (F);
62    zz_pX NTLG= convertFacCF2NTLzzpX (G);
63    mul (NTLF, NTLF, NTLG);
64    result= convertNTLzzpX2CF(NTLF, F.mvar());
65  }
66  return result;
67}
68
69static inline
70CanonicalForm
71modNTL (const CanonicalForm& F, const CanonicalForm& G)
72{
73  if (F.inCoeffDomain() && G.isUnivariate())
74    return F;
75  else if (F.inCoeffDomain() && G.inCoeffDomain())
76    return mod (F, G);
77  else if (F.isUnivariate() && G.inCoeffDomain())
78    return mod (F,G);
79   
80  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
81  ASSERT (F.level() == G.level(), "expected polys of same level");
82  if (CFFactory::gettype() == GaloisFieldDomain)
83    return mod (F, G);
84  zz_p::init (getCharacteristic());
85  Variable alpha;
86  CanonicalForm result;
87  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
88  {
89    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
90    zz_pE::init (NTLMipo);
91    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
92    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
93    rem (NTLF, NTLF, NTLG);
94    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
95  }
96  else
97  {
98    zz_pX NTLF= convertFacCF2NTLzzpX (F);
99    zz_pX NTLG= convertFacCF2NTLzzpX (G);
100    rem (NTLF, NTLF, NTLG);
101    result= convertNTLzzpX2CF(NTLF, F.mvar());
102  }
103  return result;
104}
105
106static inline
107CanonicalForm
108divNTL (const CanonicalForm& F, const CanonicalForm& G)
109{
110  if (F.inCoeffDomain() && G.isUnivariate())
111    return F;
112  else if (F.inCoeffDomain() && G.inCoeffDomain())
113    return div (F, G);
114  else if (F.isUnivariate() && G.inCoeffDomain())
115    return div (F,G);
116
117  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
118  ASSERT (F.level() == G.level(), "expected polys of same level");
119  if (CFFactory::gettype() == GaloisFieldDomain)
120    return div (F, G);
121  zz_p::init (getCharacteristic());
122  Variable alpha;
123  CanonicalForm result;
124  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
125  {
126    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
127    zz_pE::init (NTLMipo);
128    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
129    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
130    div (NTLF, NTLF, NTLG);
131    result= convertNTLzz_pEX2CF(NTLF, F.mvar(), alpha);
132  }
133  else
134  {
135    zz_pX NTLF= convertFacCF2NTLzzpX (F);
136    zz_pX NTLG= convertFacCF2NTLzzpX (G);
137    div (NTLF, NTLF, NTLG);
138    result= convertNTLzzpX2CF(NTLF, F.mvar());
139  }
140  return result;
141}
142
143/*static inline
144void
145divremNTL (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
146           CanonicalForm& R)
147{
148  if (F.inCoeffDomain() && G.isUnivariate())
149  {
150    R= F;
151    Q= 0;
152  }
153  else if (F.inCoeffDomain() && G.inCoeffDomain())
154  {
155    divrem (F, G, Q, R);
156    return;
157  }
158  else if (F.isUnivariate() && G.inCoeffDomain())
159  {
160    divrem (F, G, Q, R);
161    return;
162  }
163
164  ASSERT (F.isUnivariate() && G.isUnivariate(), "expected univariate polys");
165  ASSERT (F.level() == G.level(), "expected polys of same level");
166  if (CFFactory::gettype() == GaloisFieldDomain)
167  {
168    divrem (F, G, Q, R);
169    return;
170  }
171  zz_p::init (getCharacteristic());
172  Variable alpha;
173  CanonicalForm result;
174  if (hasFirstAlgVar (F, alpha) || hasFirstAlgVar (G, alpha))
175  {
176    zz_pX NTLMipo= convertFacCF2NTLzzpX(getMipo (alpha));
177    zz_pE::init (NTLMipo);
178    zz_pEX NTLF= convertFacCF2NTLzz_pEX (F, NTLMipo);
179    zz_pEX NTLG= convertFacCF2NTLzz_pEX (G, NTLMipo);
180    zz_pEX NTLQ;
181    zz_pEX NTLR;
182    DivRem (NTLQ, NTLR, NTLF, NTLG);
183    Q= convertNTLzz_pEX2CF(NTLQ, F.mvar(), alpha);
184    R= convertNTLzz_pEX2CF(NTLR, F.mvar(), alpha);
185    return;
186  }
187  else
188  {
189    zz_pX NTLF= convertFacCF2NTLzzpX (F);
190    zz_pX NTLG= convertFacCF2NTLzzpX (G);
191    zz_pX NTLQ;
192    zz_pX NTLR;
193    DivRem (NTLQ, NTLR, NTLF, NTLG);
194    Q= convertNTLzzpX2CF(NTLQ, F.mvar());
195    R= convertNTLzzpX2CF(NTLR, F.mvar());
196    return;
197  }
198}*/
199
200CanonicalForm mod (const CanonicalForm& F, const CFList& M) 
201{
202  CanonicalForm A= F;
203  for (CFListIterator i= M; i.hasItem(); i++) 
204    A= mod (A, i.getItem());
205  return A;
206}
207
208CanonicalForm mulMod2 (const CanonicalForm& A, const CanonicalForm& B, 
209                       const CanonicalForm& M)
210{
211  if (A.isZero() || B.isZero())
212    return 0;
213
214  ASSERT (M.isUnivariate(), "M must be univariate");
215
216  CanonicalForm F= mod (A, M);
217  CanonicalForm G= mod (B, M);
218  if (F.inCoeffDomain() || G.inCoeffDomain())
219    return F*G;
220  Variable y= M.mvar();
221  int degF= degree (F, y);
222  int degG= degree (G, y);
223
224  if ((degF < 1 && degG < 1) && (F.isUnivariate() && G.isUnivariate()) && 
225      (F.level() == G.level()))
226  { 
227    CanonicalForm result= mulNTL (F, G);
228    return mod (result, M);
229  }
230  else if (degF <= 1 && degG <= 1)
231  { 
232    CanonicalForm result= F*G;
233    return mod (result, M);
234  }
235 
236  int m= (int) ceil (degree (M)/2.0);
237  if (degF >= m || degG >= m)
238  {
239    CanonicalForm MLo= power (y, m);
240    CanonicalForm MHi= power (y, degree (M) - m);
241    CanonicalForm F0= mod (F, MLo);
242    CanonicalForm F1= div (F, MLo);
243    CanonicalForm G0= mod (G, MLo);
244    CanonicalForm G1= div (G, MLo);
245    CanonicalForm F0G1= mulMod2 (F0, G1, MHi);
246    CanonicalForm F1G0= mulMod2 (F1, G0, MHi);
247    CanonicalForm F0G0= mulMod2 (F0, G0, M);
248    return F0G0 + MLo*(F0G1 + F1G0);
249  }
250  else
251  {
252    m= (int) ceil (tmax (degF, degG)/2.0);
253    CanonicalForm yToM= power (y, m);
254    CanonicalForm F0= mod (F, yToM);
255    CanonicalForm F1= div (F, yToM);
256    CanonicalForm G0= mod (G, yToM);
257    CanonicalForm G1= div (G, yToM);
258    CanonicalForm H00= mulMod2 (F0, G0, M);
259    CanonicalForm H11= mulMod2 (F1, G1, M);
260    CanonicalForm H01= mulMod2 (F0 + F1, G0 + G1, M);
261    return H11*yToM*yToM + (H01 - H11 - H00)*yToM + H00;
262  } 
263  DEBOUTLN (cerr, "fatal end in mulMod2");
264}
265
266CanonicalForm mulMod (const CanonicalForm& A, const CanonicalForm& B, 
267                      const CFList& MOD)
268{
269  if (A.isZero() || B.isZero())
270    return 0;
271
272  if (MOD.length() == 1)
273    return mulMod2 (A, B, MOD.getLast());
274
275  CanonicalForm M= MOD.getLast();
276  CanonicalForm F= mod (A, M);
277  CanonicalForm G= mod (B, M);
278  if (F.inCoeffDomain() || G.inCoeffDomain())
279    return F*G;
280  Variable y= M.mvar();
281  int degF= degree (F, y);
282  int degG= degree (G, y);
283
284  if ((degF <= 1 && F.level() <= M.level()) && 
285      (degG <= 1 && G.level() <= M.level()))
286  {
287    CFList buf= MOD;
288    buf.removeLast();
289    if (degF == 1 && degG == 1)
290    {
291      CanonicalForm F0= mod (F, y);
292      CanonicalForm F1= div (F, y);
293      CanonicalForm G0= mod (G, y);
294      CanonicalForm G1= div (G, y);
295      if (degree (M) > 2)
296      {
297        CanonicalForm H00= mulMod (F0, G0, buf);
298        CanonicalForm H11= mulMod (F1, G1, buf);
299        CanonicalForm H01= mulMod (F0 + F1, G0 + G1, buf);
300        return H11*y*y + (H01 - H00 - H11)*y + H00;
301      }
302      else //here degree (M) == 2
303      {
304        buf.append (y);
305        CanonicalForm F0G1= mulMod (F0, G1, buf);
306        CanonicalForm F1G0= mulMod (F1, G0, buf);
307        CanonicalForm F0G0= mulMod (F0, G0, MOD);
308        CanonicalForm result= F0G0 + y*(F0G1 + F1G0);
309        return result;
310      }
311    }
312    else if (degF == 1 && degG == 0)
313      return mulMod (div (F, y), G, buf)*y + mulMod (mod (F, y), G, buf);
314    else if (degF == 0 && degG == 1)
315      return mulMod (div (G, y), F, buf)*y + mulMod (mod (G, y), F, buf);
316    else
317      return mulMod (F, G, buf);
318  }
319  int m= (int) ceil (degree (M)/2.0);
320  if (degF >= m || degG >= m)
321  {
322    CanonicalForm MLo= power (y, m);
323    CanonicalForm MHi= power (y, degree (M) - m);
324    CanonicalForm F0= mod (F, MLo);
325    CanonicalForm F1= div (F, MLo);
326    CanonicalForm G0= mod (G, MLo);
327    CanonicalForm G1= div (G, MLo);
328    CFList buf= MOD;
329    buf.removeLast();
330    buf.append (MHi);
331    CanonicalForm F0G1= mulMod (F0, G1, buf);
332    CanonicalForm F1G0= mulMod (F1, G0, buf);
333    CanonicalForm F0G0= mulMod (F0, G0, MOD);
334    return F0G0 + MLo*(F0G1 + F1G0);
335  }
336  else
337  {
338    m= (int) ceil (tmax (degF, degG)/2.0);
339    CanonicalForm yToM= power (y, m);
340    CanonicalForm F0= mod (F, yToM);
341    CanonicalForm F1= div (F, yToM);
342    CanonicalForm G0= mod (G, yToM);
343    CanonicalForm G1= div (G, yToM);
344    CanonicalForm H00= mulMod (F0, G0, MOD);
345    CanonicalForm H11= mulMod (F1, G1, MOD);
346    CanonicalForm H01= mulMod (F0 + F1, G0 + G1, MOD);
347    return H11*yToM*yToM + (H01 - H11 - H00)*yToM + H00;
348  } 
349  DEBOUTLN (cerr, "fatal end in mulMod");
350}
351
352CanonicalForm prodMod (const CFList& L, const CanonicalForm& M) 
353{
354  if (L.isEmpty())
355    return 1;
356  int l= L.length();
357  if (l == 1)
358    return mod (L.getFirst(), M);
359  else if (l == 2) {
360    CanonicalForm result= mulMod2 (L.getFirst(), L.getLast(), M);
361    return result;
362  }
363  else
364  {
365    l /= 2;
366    CFList tmp1, tmp2;
367    CFListIterator i= L;
368    CanonicalForm buf1, buf2;
369    for (int j= 1; j <= l; j++, i++) 
370      tmp1.append (i.getItem());
371    tmp2= Difference (L, tmp1);
372    buf1= prodMod (tmp1, M);
373    buf2= prodMod (tmp2, M);
374    CanonicalForm result= mulMod2 (buf1, buf2, M);
375    return result;
376  } 
377}
378
379CanonicalForm prodMod (const CFList& L, const CFList& M) 
380{
381  if (L.isEmpty())
382    return 1;
383  else if (L.length() == 1)
384    return L.getFirst();
385  else if (L.length() == 2)
386    return mulMod (L.getFirst(), L.getLast(), M);
387  else
388  {
389    int l= L.length()/2;
390    CFListIterator i= L;
391    CFList tmp1, tmp2;
392    CanonicalForm buf1, buf2;
393    for (int j= 1; j <= l; j++, i++) 
394      tmp1.append (i.getItem());
395    tmp2= Difference (L, tmp1);
396    buf1= prodMod (tmp1, M);
397    buf2= prodMod (tmp2, M);
398    return mulMod (buf1, buf2, M);
399  }
400}
401
402static inline
403CFList split (const CanonicalForm& F, const int m, const Variable& x) 
404{
405  CanonicalForm A= F;
406  CanonicalForm buf= 0;
407  bool swap= false;
408  if (degree (A, x) <= 0)
409    return CFList(A);
410  else if (x.level() != A.level())
411  {
412    swap= true;
413    A= swapvar (A, x, A.mvar());
414  }
415
416  int j= (int) floor ((double) degree (A)/ m);
417  CFList result; 
418  CFIterator i= A;
419  for (; j >= 0; j--)
420  {
421    while (i.hasTerms() && i.exp() - j*m >= 0) 
422    {
423      if (swap)
424        buf += i.coeff()*power (A.mvar(), i.exp() - j*m);
425      else
426        buf += i.coeff()*power (x, i.exp() - j*m);
427      i++;
428    }
429    if (swap)
430      result.append (swapvar (buf, x, F.mvar()));
431    else
432      result.append (buf); 
433    buf= 0;
434  }
435  return result; 
436}
437
438static inline
439void divrem32 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q, 
440               CanonicalForm& R, const CFList& M);
441
442static inline 
443void divrem21 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q, 
444               CanonicalForm& R, const CFList& M)
445{
446  CanonicalForm A= mod (F, M);
447  CanonicalForm B= mod (G, M);
448  Variable x= Variable (1);
449  int degB= degree (B, x);
450  int degA= degree (A, x);
451  if (degA < degB)
452  {
453    Q= 0;
454    R= A;
455    return;
456  }
457  ASSERT (2*degB > degA, "expected degree (F, 1) < 2*degree (G, 1)");
458  if (degB < 1)
459  {
460    divrem (A, B, Q, R);
461    Q= mod (Q, M);
462    R= mod (R, M);
463    return;
464  }
465 
466  int m= (int) ceil ((double) (degB + 1)/2.0) + 1; 
467  CFList splitA= split (A, m, x);
468  CFList splitB= split (B, m, x);
469  if (splitA.length() == 3)
470    splitA.insert (0);
471  if (splitA.length() == 2)
472  {
473    splitA.insert (0);
474    splitA.insert (0);
475  } 
476  if (splitA.length() == 1)
477  {
478    splitA.insert (0);
479    splitA.insert (0);
480    splitA.insert (0);
481  }
482
483  CanonicalForm xToM= power (x, m);
484
485  CFListIterator i= splitA;
486  CanonicalForm H= i.getItem();
487  i++;
488  H *= xToM;
489  H += i.getItem();
490  i++;
491  H *= xToM;
492  H += i.getItem();
493  i++;
494
495  divrem32 (H, B, Q, R, M);
496
497  CFList splitR= split (R, m, x);
498  if (splitR.length() == 1)
499    splitR.insert (0);
500
501  H= splitR.getFirst();
502  H *= xToM;
503  H += splitR.getLast();
504  H *= xToM;
505  H += i.getItem();
506
507  CanonicalForm bufQ;
508  divrem32 (H, B, bufQ, R, M);
509
510  Q *= xToM;
511  Q += bufQ;
512  return;
513}
514
515static inline
516void divrem32 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q, 
517               CanonicalForm& R, const CFList& M) 
518{
519  CanonicalForm A= mod (F, M);
520  CanonicalForm B= mod (G, M);
521  Variable x= Variable (1);
522  int degB= degree (B, x);
523  int degA= degree (A, x);
524  if (degA < degB) 
525  {
526    Q= 0;
527    R= A;
528    return;
529  }
530  ASSERT (3*(degB/2) > degA, "expected degree (F, 1) < 3*(degree (G, 1)/2)");
531  if (degB < 1)
532  {
533    divrem (A, B, Q, R);
534    Q= mod (Q, M);
535    R= mod (R, M);
536    return;
537  }
538  int m= (int) ceil ((double) (degB + 1)/ 2.0);
539
540  CFList splitA= split (A, m, x);
541  CFList splitB= split (B, m, x);
542
543  if (splitA.length() == 2)
544  {
545    splitA.insert (0);
546  }
547  if (splitA.length() == 1)
548  {
549    splitA.insert (0);
550    splitA.insert (0);
551  }
552  CanonicalForm xToM= power (x, m);
553
554  CanonicalForm H;
555  CFListIterator i= splitA;
556  i++;
557
558  if (degree (splitA.getFirst(), x) < degree (splitB.getFirst(), x))
559  {
560    H= splitA.getFirst()*xToM + i.getItem();
561    divrem21 (H, splitB.getFirst(), Q, R, M);
562  }
563  else 
564  {
565    R= splitA.getFirst()*xToM + i.getItem() + splitB.getFirst() - 
566       splitB.getFirst()*xToM;
567    Q= xToM - 1;
568  }
569
570  H= mulMod (Q, splitB.getLast(), M);
571
572  R= R*xToM + splitA.getLast() - H;
573
574  while (degree (R, x) >= degB)
575  {
576    xToM= power (x, degree (R, x) - degB);
577    Q += LC (R, x)*xToM;
578    R -= mulMod (LC (R, x), B, M)*xToM;
579    Q= mod (Q, M);
580    R= mod (R, M);
581  }
582
583  return;
584}
585
586void divrem2 (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
587              CanonicalForm& R, const CanonicalForm& M) 
588{
589  CanonicalForm A= mod (F, M);
590  CanonicalForm B= mod (G, M);
591  Variable x= Variable (1);
592  int degB= degree (B, x);
593  if (degB > degree (A, x)) 
594  {
595    Q= 0;
596    R= A;
597    return;
598  }
599
600  CFList splitA= split (A, degB, x);
601
602  CanonicalForm xToDegB= power (x, degB);
603  CanonicalForm H, bufQ;
604  Q= 0;
605  CFListIterator i= splitA;
606  H= i.getItem()*xToDegB;
607  i++;
608  H += i.getItem();
609  CFList buf;
610  while (i.hasItem()) 
611  {
612    buf= CFList (M);
613    divrem21 (H, B, bufQ, R, buf);
614    i++;
615    if (i.hasItem())
616      H= R*xToDegB + i.getItem();
617    Q *= xToDegB;
618    Q += bufQ; 
619  }
620  return;
621}
622
623void divrem (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
624             CanonicalForm& R, const CFList& MOD)
625{
626  CanonicalForm A= mod (F, MOD);
627  CanonicalForm B= mod (G, MOD);
628  Variable x= Variable (1);
629  int degB= degree (B, x);
630  if (degB > degree (A, x)) 
631  {
632    Q= 0;
633    R= A;
634    return;
635  }
636
637  if (degB == 0)
638  {
639    divrem (A, B, Q, R);
640    Q= mod (Q, MOD);
641    R= mod (R, MOD);
642    return;
643  }
644  CFList splitA= split (A, degB, x);
645
646  CanonicalForm xToDegB= power (x, degB);
647  CanonicalForm H, bufQ;
648  Q= 0;
649  CFListIterator i= splitA;
650  H= i.getItem()*xToDegB;
651  i++;
652  H += i.getItem();
653  while (i.hasItem()) 
654  {
655    divrem21 (H, B, bufQ, R, MOD);
656    i++;
657    if (i.hasItem())
658      H= R*xToDegB + i.getItem();
659    Q *= xToDegB;
660    Q += bufQ; 
661  }
662  return;
663}
664
665void sortList (CFList& list, const Variable& x) 
666{ 
667  int l= 1;
668  int k= 1;
669  CanonicalForm buf;
670  CFListIterator m;
671  for (CFListIterator i= list; l <= list.length(); i++, l++) 
672  {
673    for (CFListIterator j= list; k <= list.length() - l; k++) 
674    {
675      m= j;
676      m++;
677      if (degree (j.getItem(), x) > degree (m.getItem(), x)) 
678      {
679        buf= m.getItem();
680        m.getItem()= j.getItem();
681        j.getItem()= buf;
682        j++;
683        j.getItem()= m.getItem();
684      } 
685      else
686        j++;
687    }
688    k= 1;
689  }
690}
691
692static inline
693CFList diophantine (const CanonicalForm& F, const CFList& factors) 
694{
695  CanonicalForm buf1, buf2, buf3, S, T;
696  CFListIterator i= factors;
697  CFList result;
698  if (i.hasItem())
699    i++;
700  buf1= F/factors.getFirst(); 
701  buf2= divNTL (F, i.getItem());
702  buf3= extgcd (buf1, buf2, S, T);
703  result.append (S);
704  result.append (T);
705  if (i.hasItem())
706    i++;
707  for (; i.hasItem(); i++)
708  {
709    buf1= divNTL (F, i.getItem());
710    buf3= extgcd (buf3, buf1, S, T);
711    CFListIterator k= factors;
712    for (CFListIterator j= result; j.hasItem(); j++, k++)
713    {
714      j.getItem()= mulNTL (j.getItem(), S);
715      j.getItem()= modNTL (j.getItem(), k.getItem());
716    }
717    result.append (T);
718  }
719  return result;
720}
721
722void 
723henselStep12 (const CanonicalForm& F, const CFList& factors, 
724              CFArray& bufFactors, const CFList& diophant, CFMatrix& M,
725              CFArray& Pi, int j)
726{
727  CanonicalForm E;
728  CanonicalForm xToJ= power (F.mvar(), j);
729  Variable x= F.mvar();
730  // compute the error
731  if (j == 1)
732    E= F[j]; 
733  else
734  {
735    if (degree (Pi [factors.length() - 2], x) > 0) 
736      E= F[j] - Pi [factors.length() - 2] [j];
737    else
738      E= F[j]; 
739  }
740
741  CFArray buf= CFArray (diophant.length());
742  bufFactors[0]= mod (factors.getFirst(), power (F.mvar(), j + 1));
743  int k= 0;
744  CanonicalForm remainder;
745  // actual lifting
746  for (CFListIterator i= diophant; i.hasItem(); i++, k++) 
747  {
748    if (degree (bufFactors[k], x) > 0)
749    {
750      if (k > 0)
751        remainder= modNTL (E, bufFactors[k] [0]);
752      else
753        remainder= E;
754    }
755    else
756      remainder= modNTL (E, bufFactors[k]);
757
758    buf[k]= mulNTL (i.getItem(), remainder);
759    if (degree (bufFactors[k], x) > 0)
760      buf[k]= modNTL (buf[k], bufFactors[k] [0]);
761    else 
762      buf[k]= modNTL (buf[k], bufFactors[k]); 
763  }
764  for (k= 1; k < factors.length(); k++)
765    bufFactors[k] += xToJ*buf[k];
766
767  // update Pi [0]
768  int degBuf0= degree (bufFactors[0], x);
769  int degBuf1= degree (bufFactors[1], x);
770  if (degBuf0 > 0 && degBuf1 > 0)
771    M (j + 1, 1)= mulNTL (bufFactors[0] [j], bufFactors[1] [j]);
772  CanonicalForm uIZeroJ;
773  if (j == 1)
774  {
775    if (degBuf0 > 0 && degBuf1 > 0)
776      uIZeroJ= mulNTL ((bufFactors[0] [0] + bufFactors[0] [j]),
777                  (bufFactors[1] [0] + buf[1])) - M(1, 1) - M(j + 1, 1);
778    else if (degBuf0 > 0)
779      uIZeroJ= mulNTL (bufFactors[0] [j], bufFactors[1]);
780    else if (degBuf1 > 0)
781      uIZeroJ= mulNTL (bufFactors[0], buf[1]);
782    else
783      uIZeroJ= 0;
784    Pi [0] += xToJ*uIZeroJ; 
785  } 
786  else
787  {
788    if (degBuf0 > 0 && degBuf1 > 0)
789      uIZeroJ= mulNTL ((bufFactors[0] [0] + bufFactors[0] [j]),
790                  (bufFactors[1] [0] + buf[1])) - M(1, 1) - M(j + 1, 1);
791    else if (degBuf0 > 0)
792      uIZeroJ= mulNTL (bufFactors[0] [j], bufFactors[1]);
793    else if (degBuf1 > 0)
794      uIZeroJ= mulNTL (bufFactors[0], buf[1]);
795    else
796      uIZeroJ= 0;
797    Pi [0] += xToJ*uIZeroJ; 
798  }
799  CFArray tmp= CFArray (factors.length() - 1);
800  for (k= 0; k < factors.length() - 1; k++)
801    tmp[k]= 0;
802  CFIterator one, two;
803  one= bufFactors [0];
804  two= bufFactors [1];
805  if (degBuf0 > 0 && degBuf1 > 0)
806  {
807    for (k= 1; k <= (int) ceil (j/2.0); k++)
808    { 
809      if (k != j - k + 1)
810      {
811        if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
812        {
813          tmp[0] += mulNTL ((bufFactors[0] [k] + one.coeff()), (bufFactors[1] [k] +
814                     two.coeff())) - M (k + 1, 1) - M (j - k + 2, 1);
815          one++;
816          two++;
817        }
818        else if (one.exp() == j - k + 1)
819        {
820          tmp[0] += mulNTL ((bufFactors[0] [k] + one.coeff()), bufFactors[1] [k]) - 
821                     M (k + 1, 1);
822          one++;
823        }
824        else if (two.exp() == j - k + 1)
825        {
826          tmp[0] += mulNTL (bufFactors[0] [k], (bufFactors[1] [k] + two.coeff())) - 
827                    M (k + 1, 1);
828          two++;
829        }
830      }
831      else
832      {
833        tmp[0] += M (k + 1, 1);
834      }
835    }
836  }
837  Pi [0] += tmp[0]*xToJ*F.mvar();
838
839  // update Pi [l]
840  int degPi, degBuf;
841  for (int l= 1; l < factors.length() - 1; l++) 
842  {
843    degPi= degree (Pi [l - 1], x);
844    degBuf= degree (bufFactors[l + 1], x);
845    if (degPi > 0 && degBuf > 0)
846      M (j + 1, l + 1)= mulNTL (Pi [l - 1] [j], bufFactors[l + 1] [j]); 
847    if (j == 1)
848    {
849      if (degPi > 0 && degBuf > 0)
850        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [0] + Pi [l - 1] [j],
851                  bufFactors[l + 1] [0] + buf[l + 1]) - M (j + 1, l +1) - 
852                  M (1, l + 1));
853      else if (degPi > 0)
854        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [j], bufFactors[l + 1]));
855      else if (degBuf > 0)
856        Pi [l] += xToJ*(mulNTL (Pi [l - 1], buf[l + 1]));
857    }
858    else
859    {
860      if (degPi > 0 && degBuf > 0)
861      {
862        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
863        uIZeroJ += mulNTL (Pi [l - 1] [0], buf [l + 1]); 
864      }
865      else if (degPi > 0)
866        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1]);
867      else if (degBuf > 0)
868      {
869        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
870        uIZeroJ += mulNTL (Pi [l - 1], buf[l + 1]);
871      }
872      Pi[l] += xToJ*uIZeroJ;
873    }
874    one= bufFactors [l + 1];
875    two= Pi [l - 1];
876    if (two.exp() == j + 1)
877    {
878      if (degBuf > 0 && degPi > 0)
879      {
880          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1][0]);
881          two++;
882      }
883      else if (degPi > 0)
884      {     
885          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1]);
886          two++;
887      } 
888    }
889    if (degBuf > 0 && degPi > 0) 
890    {
891      for (k= 1; k <= (int) ceil (j/2.0); k++)
892      { 
893        if (k != j - k + 1)
894        {
895          if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
896          {
897            tmp[l] += mulNTL ((bufFactors[l + 1] [k] + one.coeff()), (Pi[l - 1] [k] +
898                       two.coeff())) - M (k + 1, l + 1) - M (j - k + 2, l + 1);
899            one++;
900            two++;
901          }
902          else if (one.exp() == j - k + 1)
903          {
904            tmp[l] += mulNTL ((bufFactors[l + 1] [k] + one.coeff()), Pi[l - 1] [k]) - 
905                       M (k + 1, l + 1);     
906            one++;
907          }
908          else if (two.exp() == j - k + 1)
909          {
910            tmp[l] += mulNTL (bufFactors[l + 1] [k], (Pi[l - 1] [k] + two.coeff())) - 
911                      M (k + 1, l + 1);
912            two++;
913          }
914        }
915        else
916          tmp[l] += M (k + 1, l + 1);
917      } 
918    } 
919    Pi[l] += tmp[l]*xToJ*F.mvar();
920  }
921  return;
922}
923
924void 
925henselLift12 (const CanonicalForm& F, CFList& factors, int l, CFArray& Pi, 
926              CFList& diophant, CFMatrix& M) 
927{
928  sortList (factors, Variable (1));
929  Pi= CFArray (factors.length() - 1);
930  CFListIterator j= factors;
931  diophant= diophantine (F[0], factors);
932  DEBOUTLN (cerr, "diophant= " << diophant);
933  j++;
934  Pi [0]= mulNTL (j.getItem(), mod (factors.getFirst(), F.mvar()));
935  M (1, 1)= Pi [0];
936  int i= 1;
937  if (j.hasItem())
938    j++;
939  for (; j.hasItem(); j++, i++) 
940  {
941    Pi [i]= mulNTL (Pi [i - 1], j.getItem());
942    M (1, i + 1)= Pi [i];
943  }
944  CFArray bufFactors= CFArray (factors.length());
945  i= 0;
946  for (CFListIterator k= factors; k.hasItem(); i++, k++)
947  {
948    if (i == 0)
949      bufFactors[i]= mod (k.getItem(), F.mvar());
950    else
951      bufFactors[i]= k.getItem();
952  }
953  for (i= 1; i < l; i++)
954    henselStep12 (F, factors, bufFactors, diophant, M, Pi, i);
955
956  CFListIterator k= factors;
957  for (i= 0; i < factors.length (); i++, k++)
958    k.getItem()= bufFactors[i];
959  factors.removeFirst();
960  return;
961}
962
963void 
964henselStep122 (const CanonicalForm& F, const CFList& factors, 
965              CFArray& bufFactors, const CFList& diophant, CFMatrix& M,
966              CFArray& Pi, int j, const CFArray& LCs)
967{
968  Variable x= F.mvar();
969  CanonicalForm xToJ= power (x, j);
970 
971  CanonicalForm E;
972  // compute the error
973  if (degree (Pi [factors.length() - 2], x) > 0) 
974    E= F[j] - Pi [factors.length() - 2] [j];
975  else
976    E= F[j]; 
977
978  CFArray buf= CFArray (diophant.length());
979
980  int k= 0;
981  CanonicalForm remainder;
982  // actual lifting
983  for (CFListIterator i= diophant; i.hasItem(); i++, k++) 
984  {
985    if (degree (bufFactors[k], x) > 0)
986      remainder= modNTL (E, bufFactors[k] [0]);
987    else
988      remainder= modNTL (E, bufFactors[k]);
989    buf[k]= mulNTL (i.getItem(), remainder);
990    if (degree (bufFactors[k], x) > 0)
991      buf[k]= modNTL (buf[k], bufFactors[k] [0]);
992    else 
993      buf[k]= modNTL (buf[k], bufFactors[k]); 
994  }
995 
996  for (k= 0; k < factors.length(); k++)
997    bufFactors[k] += xToJ*buf[k];
998   
999  // update Pi [0]
1000  int degBuf0= degree (bufFactors[0], x);
1001  int degBuf1= degree (bufFactors[1], x);
1002  if (degBuf0 > 0 && degBuf1 > 0)
1003  {
1004    M (j + 1, 1)= mulNTL (bufFactors[0] [j], bufFactors[1] [j]);
1005    if (j + 2 <= M.rows())
1006      M (j + 2, 1)= mulNTL (bufFactors[0] [j + 1], bufFactors[1] [j + 1]);
1007  }
1008  CanonicalForm uIZeroJ;
1009  if (degBuf0 > 0 && degBuf1 > 0)
1010    uIZeroJ= mulNTL (bufFactors[0] [0], buf [1]) + mulNTL (bufFactors[1] [0], buf[0]);
1011  else if (degBuf0 > 0)
1012    uIZeroJ= mulNTL (buf[0], bufFactors[1]);
1013  else if (degBuf1 > 0)
1014    uIZeroJ= mulNTL (bufFactors[0], buf [1]);
1015  else
1016    uIZeroJ= 0;
1017  Pi [0] += xToJ*uIZeroJ;
1018
1019  CFArray tmp= CFArray (factors.length() - 1);
1020  for (k= 0; k < factors.length() - 1; k++)
1021    tmp[k]= 0;
1022  CFIterator one, two;
1023  one= bufFactors [0];
1024  two= bufFactors [1];
1025  if (degBuf0 > 0 && degBuf1 > 0)
1026  {
1027    while (one.exp() > j) one++;
1028    while (two.exp() > j) two++;
1029    for (k= 1; k <= (int) ceil (j/2.0); k++)
1030    { 
1031      if (k != j - k + 1)
1032      {
1033        if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
1034        {
1035          tmp[0] += mulNTL ((bufFactors[0] [k] + one.coeff()), (bufFactors[1] [k] +
1036                     two.coeff())) - M (k + 1, 1) - M (j - k + 2, 1);
1037          one++;
1038          two++;
1039        }
1040        else if (one.exp() == j - k + 1)
1041        {
1042          tmp[0] += mulNTL ((bufFactors[0] [k] + one.coeff()), bufFactors[1] [k]) - 
1043                     M (k + 1, 1);
1044          one++;
1045        }
1046        else if (two.exp() == j - k + 1)
1047        {
1048          tmp[0] += mulNTL (bufFactors[0] [k], (bufFactors[1] [k] + two.coeff())) - 
1049                    M (k + 1, 1);
1050          two++;
1051        }
1052      }
1053      else
1054        tmp[0] += M (k + 1, 1);
1055    }
1056
1057    if (j + 2 <= M.rows())
1058    {
1059      if (degBuf0 >= j + 1 && degBuf1 >= j + 1)
1060        tmp [0] += mulNTL ((bufFactors [0] [j + 1]+ bufFactors [0] [0]), (bufFactors [1] [j + 1] + bufFactors [1] [0]))
1061               - M(1,1) - M (j + 2,1);
1062      else if (degBuf0 >= j + 1)
1063        tmp[0] += mulNTL (bufFactors [0] [j+1], bufFactors [1] [0]);
1064      else if (degBuf1 >= j + 1)
1065        tmp[0] += mulNTL (bufFactors [0] [0], bufFactors [1] [j + 1]);
1066    }
1067  }
1068  Pi [0] += tmp[0]*xToJ*F.mvar();
1069 
1070  /*// update Pi [l]
1071  int degPi, degBuf;
1072  for (int l= 1; l < factors.length() - 1; l++)
1073  {
1074    degPi= degree (Pi [l - 1], x);
1075    degBuf= degree (bufFactors[l + 1], x);
1076    if (degPi > 0 && degBuf > 0)
1077      M (j + 1, l + 1)= mulNTL (Pi [l - 1] [j], bufFactors[l + 1] [j]); 
1078    if (j == 1)
1079    {
1080      if (degPi > 0 && degBuf > 0)
1081        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [0] + Pi [l - 1] [j],
1082                  bufFactors[l + 1] [0] + buf[l + 1]) - M (j + 1, l +1) -
1083                  M (1, l + 1));
1084      else if (degPi > 0)
1085        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [j], bufFactors[l + 1]));
1086      else if (degBuf > 0)
1087        Pi [l] += xToJ*(mulNTL (Pi [l - 1], buf[l + 1]));
1088    }
1089    else
1090    {
1091      if (degPi > 0 && degBuf > 0)
1092      {
1093        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
1094        uIZeroJ += mulNTL (Pi [l - 1] [0], buf [l + 1]);
1095      }
1096      else if (degPi > 0)
1097        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1]);
1098      else if (degBuf > 0)
1099      {
1100        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
1101        uIZeroJ += mulNTL (Pi [l - 1], buf[l + 1]);
1102      }
1103      Pi[l] += xToJ*uIZeroJ;
1104    }
1105    one= bufFactors [l + 1];
1106    two= Pi [l - 1];
1107    if (two.exp() == j + 1)
1108    {
1109      if (degBuf > 0 && degPi > 0)
1110      {
1111          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1][0]);
1112          two++;
1113      }
1114      else if (degPi > 0)
1115      {     
1116          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1]);
1117          two++;
1118      }
1119    }
1120    if (degBuf > 0 && degPi > 0)
1121    {
1122      for (k= 1; k <= (int) ceil (j/2.0); k++)
1123      { 
1124        if (k != j - k + 1)
1125        {
1126          if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
1127          {
1128            tmp[l] += mulNTL ((bufFactors[l + 1] [k] + one.coeff()), (Pi[l - 1] [k] +
1129                       two.coeff())) - M (k + 1, l + 1) - M (j - k + 2, l + 1);
1130            one++;
1131            two++;
1132          }
1133          else if (one.exp() == j - k + 1)
1134          {
1135            tmp[l] += mulNTL ((bufFactors[l + 1] [k] + one.coeff()), Pi[l - 1] [k]) -
1136                       M (k + 1, l + 1);     
1137            one++;
1138          }
1139          else if (two.exp() == j - k + 1)
1140          {
1141            tmp[l] += mulNTL (bufFactors[l + 1] [k], (Pi[l - 1] [k] + two.coeff())) -
1142                      M (k + 1, l + 1);
1143            two++;
1144          }
1145        }
1146        else
1147          tmp[l] += M (k + 1, l + 1);
1148      } 
1149    } 
1150    Pi[l] += tmp[l]*xToJ*F.mvar();
1151  }*/
1152  return;
1153}
1154
1155void 
1156henselLift122 (const CanonicalForm& F, CFList& factors, int l, CFArray& Pi, 
1157              CFList& diophant, CFMatrix& M, const CFArray& LCs, bool sort) 
1158{
1159  if (sort)
1160    sortList (factors, Variable (1));
1161  Pi= CFArray (factors.length() - 2);
1162  CFList bufFactors2= factors;
1163  bufFactors2.removeFirst();
1164  diophant.removeFirst();
1165  CFListIterator iter= diophant;
1166  CanonicalForm test= 0, test2= 0;
1167  CanonicalForm s,t;
1168  extgcd (bufFactors2.getFirst(), bufFactors2.getLast(), s, t);
1169  diophant= CFList();
1170  diophant.append (t);
1171  diophant.append (s);
1172  DEBOUTLN (cerr, "diophant= " << diophant);
1173
1174  CFArray bufFactors= CFArray (bufFactors2.length());
1175  int i= 0;
1176  for (CFListIterator k= bufFactors2; k.hasItem(); i++, k++)
1177    bufFactors[i]= replaceLc (k.getItem(), LCs [i]);
1178
1179  Variable x= F.mvar();
1180  if (degree (bufFactors[0], x) > 0 && degree (bufFactors [1], x) > 0)
1181  {
1182    M (1, 1)= mulNTL (bufFactors [0] [0], bufFactors[1] [0]);
1183    Pi [0]= M (1, 1) + (mulNTL (bufFactors [0] [1], bufFactors[1] [0]) + 
1184                        mulNTL (bufFactors [0] [0], bufFactors [1] [1]))*x;
1185  }
1186  else if (degree (bufFactors[0], x) > 0)
1187  {
1188    M (1, 1)= mulNTL (bufFactors [0] [0], bufFactors[1]);
1189    Pi [0]= M (1, 1) +
1190            mulNTL (bufFactors [0] [1], bufFactors[1])*x;
1191  }
1192  else if (degree (bufFactors[1], x) > 0)
1193  {
1194    M (1, 1)= mulNTL (bufFactors [0], bufFactors[1] [0]);
1195    Pi [0]= M (1, 1) +
1196            mulNTL (bufFactors [0], bufFactors[1] [1])*x;
1197  }
1198  else
1199  {
1200    M (1, 1)= mulNTL (bufFactors [0], bufFactors[1]);
1201    Pi [0]= M (1, 1);
1202  }         
1203
1204  for (i= 1; i < l; i++)
1205    henselStep122 (F, bufFactors2, bufFactors, diophant, M, Pi, i, LCs);
1206
1207  factors= CFList();
1208  for (i= 0; i < bufFactors.size(); i++)
1209    factors.append (bufFactors[i]);
1210  return;
1211}
1212
1213void 
1214henselLiftResume12 (const CanonicalForm& F, CFList& factors, int start, int
1215                    end, CFArray& Pi, const CFList& diophant, CFMatrix& M)
1216{
1217  CFArray bufFactors= CFArray (factors.length());
1218  int i= 0;
1219  CanonicalForm xToStart= power (F.mvar(), start);
1220  for (CFListIterator k= factors; k.hasItem(); k++, i++)
1221  {
1222    if (i == 0)
1223      bufFactors[i]= mod (k.getItem(), xToStart);
1224    else
1225      bufFactors[i]= k.getItem();
1226  }
1227  for (i= start; i < end; i++)
1228    henselStep12 (F, factors, bufFactors, diophant, M, Pi, i); 
1229 
1230  CFListIterator k= factors;
1231  for (i= 0; i < factors.length(); k++, i++)
1232    k.getItem()= bufFactors [i];
1233  factors.removeFirst();
1234  return; 
1235} 
1236
1237static inline
1238CFList
1239biDiophantine (const CanonicalForm& F, const CFList& factors, const int d)
1240{
1241  Variable y= F.mvar();
1242  CFList result;
1243  if (y.level() == 1)
1244  {
1245    result= diophantine (F, factors);
1246    return result;
1247  }
1248  else
1249  {
1250    CFList buf= factors;
1251    for (CFListIterator i= buf; i.hasItem(); i++)
1252      i.getItem()= mod (i.getItem(), y);
1253    CanonicalForm A= mod (F, y);
1254    int bufD= 1;
1255    CFList recResult= biDiophantine (A, buf, bufD);
1256    CanonicalForm e= 1;
1257    CFList p;
1258    CFArray bufFactors= CFArray (factors.length());
1259    CanonicalForm yToD= power (y, d);
1260    int k= 0;
1261    for (CFListIterator i= factors; i.hasItem(); i++, k++)
1262    {
1263      bufFactors [k]= i.getItem();
1264    }
1265    CanonicalForm b;
1266    for (k= 0; k < factors.length(); k++) //TODO compute b's faster
1267    {
1268      b= 1;
1269      if (fdivides (bufFactors[k], F))
1270        b= F/bufFactors[k];
1271      else 
1272      {
1273        for (int l= 0; l < factors.length(); l++)
1274        {
1275          if (l == k)
1276            continue;
1277          else
1278          {
1279            b= mulMod2 (b, bufFactors[l], yToD);
1280          }
1281        }
1282      }
1283      p.append (b);
1284    } 
1285
1286    CFListIterator j= p;
1287    for (CFListIterator i= recResult; i.hasItem(); i++, j++)
1288      e -= i.getItem()*j.getItem();
1289
1290    if (e.isZero())
1291      return recResult; 
1292    CanonicalForm coeffE;
1293    CFList s;
1294    result= recResult;
1295    CanonicalForm g;
1296    for (int i= 1; i < d; i++)
1297    {
1298      if (degree (e, y) > 0)
1299        coeffE= e[i];
1300      else
1301        coeffE= 0;
1302      if (!coeffE.isZero())
1303      {
1304        CFListIterator k= result;
1305        CFListIterator l= p;
1306        int ii= 0;
1307        j= recResult;
1308        for (; j.hasItem(); j++, k++, l++, ii++)
1309        {
1310          g= coeffE*j.getItem();
1311          if (degree (bufFactors[ii], y) <= 0)
1312            g= mod (g, bufFactors[ii]);
1313          else
1314            g= mod (g, bufFactors[ii][0]);
1315          k.getItem() += g*power (y, i); 
1316          e -= mulMod2 (g*power(y, i), l.getItem(), yToD);
1317          DEBOUTLN (cerr, "mod (e, power (y, i + 1))= " << 
1318                    mod (e, power (y, i + 1)));
1319        } 
1320      } 
1321      if (e.isZero())
1322        break;
1323    }
1324
1325    DEBOUTLN (cerr, "mod (e, y)= " << mod (e, y));
1326
1327#ifdef DEBUGOUTPUT
1328    CanonicalForm test= 0;
1329    j= p; 
1330    for (CFListIterator i= result; i.hasItem(); i++, j++)
1331      test += mod (i.getItem()*j.getItem(), power (y, d));
1332    DEBOUTLN (cerr, "test= " << test);
1333#endif
1334    return result;
1335  }
1336}
1337
1338static inline
1339CFList
1340multiRecDiophantine (const CanonicalForm& F, const CFList& factors, 
1341                     const CFList& recResult, const CFList& M, const int d)
1342{
1343  Variable y= F.mvar();
1344  CFList result;
1345  CFListIterator i;
1346  CanonicalForm e= 1;
1347  CFListIterator j= factors;
1348  CFList p;
1349  CFArray bufFactors= CFArray (factors.length());
1350  CanonicalForm yToD= power (y, d);
1351  int k= 0;
1352  for (CFListIterator i= factors; i.hasItem(); i++, k++)
1353    bufFactors [k]= i.getItem();
1354  CanonicalForm b;
1355  CFList buf= M;
1356  buf.removeLast();
1357  buf.append (yToD);
1358  for (k= 0; k < factors.length(); k++) //TODO compute b's faster
1359  {
1360    b= 1;
1361    if (fdivides (bufFactors[k], F))
1362      b= F/bufFactors[k];
1363    else 
1364    {
1365      for (int l= 0; l < factors.length(); l++)
1366      {
1367        if (l == k)
1368          continue;
1369        else
1370        {
1371          b= mulMod (b, bufFactors[l], buf);
1372        }
1373      }
1374    }
1375    p.append (b);
1376  } 
1377  j= p;
1378  for (CFListIterator i= recResult; i.hasItem(); i++, j++)
1379    e -= mulMod (i.getItem(), j.getItem(), M);
1380
1381  if (e.isZero())
1382    return recResult; 
1383  CanonicalForm coeffE;
1384  CFList s;
1385  result= recResult;
1386  CanonicalForm g;
1387  for (int i= 1; i < d; i++)
1388  {
1389    CanonicalForm kk= 0;
1390    if (degree (e, y) > 0)
1391      coeffE= e[i];
1392    else
1393      coeffE= 0;
1394    if (!coeffE.isZero())
1395    {
1396      CFListIterator k= result;
1397      CFListIterator l= p;
1398      j= recResult;
1399      int ii= 0;
1400      CanonicalForm dummy;
1401      for (; j.hasItem(); j++, k++, l++, ii++)
1402      {
1403        g= mulMod (coeffE, j.getItem(), M);
1404        if (degree (bufFactors[ii], y) <= 0)
1405          divrem (g, mod (bufFactors[ii], Variable (y.level() - 1)), dummy, 
1406                  g, M);
1407        else
1408          divrem (g, bufFactors[ii][0], dummy, g, M);
1409        k.getItem() += g*power (y, i);
1410        e -= mulMod (g*power (y, i), l.getItem(), M);
1411      } 
1412    }
1413    if (e.isZero())
1414      break;
1415  }
1416
1417#ifdef DEBUGOUTPUT
1418    CanonicalForm test= 0;
1419    j= p; 
1420    for (CFListIterator i= result; i.hasItem(); i++, j++)
1421      test += mod (i.getItem()*j.getItem(), power (y, d));
1422    DEBOUTLN (cerr, "test= " << test);
1423#endif
1424  return result;
1425}
1426
1427/// solve \f$ E=sum_{i= 1}^{r}{\sigma_{i}prod_{j=1, j\neq i}^{r}{f_{i}}}\f$
1428/// mod M, products contains \f$ prod_{j=1, j\neq i}^{r}{f_{i}}} \f$
1429static inline
1430CFList
1431diophantine (const CFList& recResult, const CFList& factors, 
1432             const CFList& products, const CFList& M, const CanonicalForm& E)
1433{
1434  if (M.isEmpty())
1435  {
1436    CFList result;
1437    CFListIterator j= factors;
1438    CanonicalForm buf;
1439    for (CFListIterator i= recResult; i.hasItem(); i++, j++)
1440    {
1441      ASSERT (E.isUnivariate() || E.inCoeffDomain(), 
1442              "constant or univariate poly expected");
1443      ASSERT (i.getItem().isUnivariate() || i.getItem().inCoeffDomain(), 
1444              "constant or univariate poly expected");
1445      ASSERT (j.getItem().isUnivariate() || j.getItem().inCoeffDomain(), 
1446              "constant or univariate poly expected");
1447      buf= mulNTL (E, i.getItem());
1448      result.append (modNTL (buf, j.getItem()));
1449    }
1450    return result;
1451  }
1452  Variable y= M.getLast().mvar();
1453  CFList bufFactors= factors;
1454  for (CFListIterator i= bufFactors; i.hasItem(); i++)
1455    i.getItem()= mod (i.getItem(), y);
1456  CFList bufProducts= products;
1457  for (CFListIterator i= bufProducts; i.hasItem(); i++)
1458    i.getItem()= mod (i.getItem(), y);
1459  CFList buf= M;
1460  buf.removeLast();
1461  CanonicalForm bufE= mod (E, y);
1462  CFList recDiophantine= diophantine (recResult, bufFactors, bufProducts, buf, 
1463                                      bufE);
1464
1465  CanonicalForm e= E;
1466  CFListIterator j= products;
1467  for (CFListIterator i= recDiophantine; i.hasItem(); i++, j++)
1468    e -= mulMod (i.getItem(), j.getItem(), M);
1469
1470  CFList result= recDiophantine;
1471  int d= degree (M.getLast());
1472  CanonicalForm coeffE;
1473  for (int i= 1; i < d; i++)
1474  {
1475    if (degree (e, y) > 0)
1476      coeffE= e[i];
1477    else
1478      coeffE= 0;
1479    if (!coeffE.isZero())
1480    {
1481      CFListIterator k= result;
1482      recDiophantine= diophantine (recResult, bufFactors, bufProducts, buf, 
1483                                   coeffE);
1484      CFListIterator l= products;
1485      for (j= recDiophantine; j.hasItem(); j++, k++, l++)
1486      {
1487        k.getItem() += j.getItem()*power (y, i);
1488        e -= mulMod (j.getItem()*power (y, i), l.getItem(), M);
1489      } 
1490    }
1491    if (e.isZero())
1492      break;
1493  }
1494  return result;
1495}
1496
1497// non monic case
1498static inline 
1499CFList
1500multiRecDiophantine2 (const CanonicalForm& F, const CFList& factors, 
1501                     const CFList& recResult, const CFList& M, const int d)
1502{
1503  Variable y= F.mvar();
1504  CFList result;
1505  CFListIterator i;
1506  CanonicalForm e= 1;
1507  CFListIterator j= factors;
1508  CFList p;
1509  CFArray bufFactors= CFArray (factors.length());
1510  CanonicalForm yToD= power (y, d);
1511  int k= 0;
1512  for (CFListIterator i= factors; i.hasItem(); i++, k++)
1513    bufFactors [k]= i.getItem();
1514  CanonicalForm b;
1515  CFList buf= M;
1516  buf.removeLast();
1517  buf.append (yToD);
1518  for (k= 0; k < factors.length(); k++) //TODO compute b's faster
1519  {
1520    b= 1;
1521    if (fdivides (bufFactors[k], F))
1522      b= F/bufFactors[k];
1523    else 
1524    {
1525      for (int l= 0; l < factors.length(); l++)
1526      {
1527        if (l == k)
1528          continue;
1529        else
1530        {
1531          b= mulMod (b, bufFactors[l], buf);
1532        }
1533      }
1534    }
1535    p.append (b);
1536  } 
1537  j= p;
1538  for (CFListIterator i= recResult; i.hasItem(); i++, j++)
1539    e -= mulMod (i.getItem(), j.getItem(), M);
1540  if (e.isZero())
1541    return recResult; 
1542  CanonicalForm coeffE;
1543  result= recResult;
1544  CanonicalForm g;
1545  buf.removeLast();
1546  for (int i= 1; i < d; i++)
1547  {
1548    if (degree (e, y) > 0)
1549      coeffE= e[i];
1550    else
1551      coeffE= 0;
1552    if (!coeffE.isZero())
1553    {
1554      CFListIterator k= result;
1555      CFListIterator l= p;
1556      j= recResult;
1557      int ii= 0;
1558      CanonicalForm dummy;
1559      CFList recDiophantine;
1560      CFList buf2, buf3;
1561      buf2= factors;
1562      buf3= p;
1563      for (CFListIterator iii= buf2; iii.hasItem(); iii++)
1564        iii.getItem()= mod (iii.getItem(), y);
1565      for (CFListIterator iii= buf3; iii.hasItem(); iii++)
1566        iii.getItem()= mod (iii.getItem(), y);
1567      recDiophantine= diophantine (recResult, buf2, buf3, buf, coeffE);
1568      CFListIterator iter= recDiophantine;
1569      for (; j.hasItem(); j++, k++, l++, ii++, iter++)
1570      {
1571        k.getItem() += iter.getItem()*power (y, i);
1572        e -= mulMod (iter.getItem()*power (y, i), l.getItem(), M);
1573      } 
1574    }
1575    if (e.isZero())
1576      break;
1577  }
1578
1579#ifdef DEBUGOUTPUT
1580    CanonicalForm test= 0;
1581    j= p; 
1582    for (CFListIterator i= result; i.hasItem(); i++, j++)
1583      test += mod (i.getItem()*j.getItem(), power (y, d));
1584    DEBOUTLN (cerr, "test= " << test);
1585#endif
1586  return result;
1587}
1588
1589static inline
1590void 
1591henselStep (const CanonicalForm& F, const CFList& factors, CFArray& bufFactors, 
1592            const CFList& diophant, CFMatrix& M, CFArray& Pi, int j, 
1593            const CFList& MOD) 
1594{
1595  CanonicalForm E;
1596  CanonicalForm xToJ= power (F.mvar(), j);
1597  Variable x= F.mvar();
1598  // compute the error
1599  if (j == 1)
1600  {
1601    E= F[j];
1602#ifdef DEBUGOUTPUT
1603    CanonicalForm test= 1;
1604    for (int i= 0; i < factors.length(); i++)
1605    {
1606      if (i == 0)
1607        test= mulMod (test, mod (bufFactors [i], xToJ), MOD);
1608      else
1609        test= mulMod (test, bufFactors[i], MOD);
1610    }
1611    CanonicalForm test2= mod (F-test, xToJ);
1612
1613    test2= mod (test2, MOD);
1614    DEBOUTLN (cerr, "test= " << test2);
1615#endif
1616  } 
1617  else
1618  {
1619#ifdef DEBUGOUTPUT
1620    CanonicalForm test= 1;
1621    for (int i= 0; i < factors.length(); i++)
1622    {
1623      if (i == 0)
1624        test *= mod (bufFactors [i], power (x, j));
1625      else
1626        test *= bufFactors[i];
1627    }
1628    test= mod (test, power (x, j));
1629    test= mod (test, MOD);
1630    CanonicalForm test2= mod (F, power (x, j - 1)) - mod (test, power (x, j-1));
1631    DEBOUTLN (cerr, "test= " << test2);
1632#endif
1633
1634    if (degree (Pi [factors.length() - 2], x) > 0)
1635      E= F[j] - Pi [factors.length() - 2] [j];
1636    else
1637      E= F[j];
1638  }
1639
1640  CFArray buf= CFArray (diophant.length());
1641  bufFactors[0]= mod (factors.getFirst(), power (F.mvar(), j + 1));
1642  int k= 0;
1643  // actual lifting
1644  CanonicalForm dummy, rest1;
1645  for (CFListIterator i= diophant; i.hasItem(); i++, k++) 
1646  {
1647    if (degree (bufFactors[k], x) > 0)
1648    {
1649      if (k > 0)
1650        divrem (E, bufFactors[k] [0], dummy, rest1, MOD);
1651      else
1652        rest1= E;
1653    }
1654    else
1655      divrem (E, bufFactors[k], dummy, rest1, MOD);
1656
1657    buf[k]= mulMod (i.getItem(), rest1, MOD);
1658
1659    if (degree (bufFactors[k], x) > 0)
1660      divrem (buf[k], bufFactors[k] [0], dummy, buf[k], MOD);
1661    else 
1662      divrem (buf[k], bufFactors[k], dummy, buf[k], MOD);
1663  }
1664  for (k= 1; k < factors.length(); k++)
1665    bufFactors[k] += xToJ*buf[k];
1666
1667  // update Pi [0]
1668  int degBuf0= degree (bufFactors[0], x);
1669  int degBuf1= degree (bufFactors[1], x);
1670  if (degBuf0 > 0 && degBuf1 > 0)
1671    M (j + 1, 1)= mulMod (bufFactors[0] [j], bufFactors[1] [j], MOD);
1672  CanonicalForm uIZeroJ;
1673  if (j == 1)
1674  {
1675    if (degBuf0 > 0 && degBuf1 > 0)
1676      uIZeroJ= mulMod ((bufFactors[0] [0] + bufFactors[0] [j]),
1677                  (bufFactors[1] [0] + buf[1]), MOD) - M(1, 1) - M(j + 1, 1);
1678    else if (degBuf0 > 0)
1679      uIZeroJ= mulMod (bufFactors[0] [j], bufFactors[1], MOD);
1680    else if (degBuf1 > 0)
1681      uIZeroJ= mulMod (bufFactors[0], buf[1], MOD);
1682    else
1683      uIZeroJ= 0;
1684    Pi [0] += xToJ*uIZeroJ; 
1685  } 
1686  else
1687  {
1688    if (degBuf0 > 0 && degBuf1 > 0)
1689      uIZeroJ= mulMod ((bufFactors[0] [0] + bufFactors[0] [j]), 
1690                  (bufFactors[1] [0] + buf[1]), MOD) - M(1, 1) - M(j + 1, 1);
1691    else if (degBuf0 > 0)
1692      uIZeroJ= mulMod (bufFactors[0] [j], bufFactors[1], MOD);
1693    else if (degBuf1 > 0)
1694      uIZeroJ= mulMod (bufFactors[0], buf[1], MOD);
1695    else
1696      uIZeroJ= 0;
1697    Pi [0] += xToJ*uIZeroJ; 
1698  }
1699
1700  CFArray tmp= CFArray (factors.length() - 1);
1701  for (k= 0; k < factors.length() - 1; k++)
1702    tmp[k]= 0;
1703  CFIterator one, two;
1704  one= bufFactors [0];
1705  two= bufFactors [1];
1706  if (degBuf0 > 0 && degBuf1 > 0)
1707  {
1708    for (k= 1; k <= (int) ceil (j/2.0); k++)
1709    { 
1710      if (k != j - k + 1)
1711      {
1712        if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
1713        {
1714          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()), 
1715                    (bufFactors[1] [k] + two.coeff()), MOD) - M (k + 1, 1) - 
1716                    M (j - k + 2, 1);
1717          one++;
1718          two++;
1719        }
1720        else if (one.exp() == j - k + 1)
1721        {
1722          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()), 
1723                    bufFactors[1] [k], MOD) - M (k + 1, 1);
1724          one++;
1725        }
1726        else if (two.exp() == j - k + 1)
1727        {
1728          tmp[0] += mulMod (bufFactors[0] [k], (bufFactors[1] [k] + 
1729                    two.coeff()), MOD) - M (k + 1, 1);
1730          two++;
1731        }
1732      }
1733      else
1734      {
1735        tmp[0] += M (k + 1, 1);
1736      }
1737    }
1738  }
1739  Pi [0] += tmp[0]*xToJ*F.mvar();
1740
1741  // update Pi [l]
1742  int degPi, degBuf;
1743  for (int l= 1; l < factors.length() - 1; l++) 
1744  {
1745    degPi= degree (Pi [l - 1], x);
1746    degBuf= degree (bufFactors[l + 1], x);
1747    if (degPi > 0 && degBuf > 0)
1748      M (j + 1, l + 1)= mulMod (Pi [l - 1] [j], bufFactors[l + 1] [j], MOD); 
1749    if (j == 1)
1750    {
1751      if (degPi > 0 && degBuf > 0)
1752        Pi [l] += xToJ*(mulMod ((Pi [l - 1] [0] + Pi [l - 1] [j]), 
1753                  (bufFactors[l + 1] [0] + buf[l + 1]), MOD) - M (j + 1, l +1)- 
1754                  M (1, l + 1));
1755      else if (degPi > 0)
1756        Pi [l] += xToJ*(mulMod (Pi [l - 1] [j], bufFactors[l + 1], MOD));
1757      else if (degBuf > 0)
1758        Pi [l] += xToJ*(mulMod (Pi [l - 1], buf[l + 1], MOD));
1759    }
1760    else
1761    {
1762      if (degPi > 0 && degBuf > 0)
1763      {
1764        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
1765        uIZeroJ += mulMod (Pi [l - 1] [0], buf [l + 1], MOD); 
1766      }
1767      else if (degPi > 0)
1768        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1], MOD);
1769      else if (degBuf > 0)
1770      {
1771        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
1772        uIZeroJ += mulMod (Pi [l - 1], buf[l + 1], MOD);
1773      }
1774      Pi[l] += xToJ*uIZeroJ;
1775    }
1776    one= bufFactors [l + 1];
1777    two= Pi [l - 1];
1778    if (two.exp() == j + 1)
1779    {
1780      if (degBuf > 0 && degPi > 0)
1781      {
1782          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1][0], MOD);
1783          two++;
1784      }
1785      else if (degPi > 0)
1786      {     
1787          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1], MOD);
1788          two++;
1789      } 
1790    }
1791    if (degBuf > 0 && degPi > 0) 
1792    {
1793      for (k= 1; k <= (int) ceil (j/2.0); k++)
1794      { 
1795        if (k != j - k + 1)
1796        {
1797          if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
1798          {
1799            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()), 
1800                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1) - 
1801                      M (j - k + 2, l + 1);
1802            one++;
1803            two++;
1804          }
1805          else if (one.exp() == j - k + 1)
1806          {
1807            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()), 
1808                      Pi[l - 1] [k], MOD) - M (k + 1, l + 1);     
1809            one++;
1810          }
1811          else if (two.exp() == j - k + 1)
1812          {
1813            tmp[l] += mulMod (bufFactors[l + 1] [k], 
1814                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1);
1815            two++;
1816          }
1817        }
1818        else
1819          tmp[l] += M (k + 1, l + 1);
1820      } 
1821    } 
1822    Pi[l] += tmp[l]*xToJ*F.mvar();
1823  }
1824
1825  return;
1826}
1827
1828// so far only tested for two! factor Hensel lifting
1829static inline
1830void 
1831henselStep2 (const CanonicalForm& F, const CFList& factors, CFArray& bufFactors, 
1832            const CFList& diophant, CFMatrix& M, CFArray& Pi, 
1833            const CFList& products, int j, const CFList& MOD) 
1834{
1835  CanonicalForm E;
1836  CanonicalForm xToJ= power (F.mvar(), j);
1837  Variable x= F.mvar();
1838
1839  // compute the error
1840#ifdef DEBUGOUTPUT
1841    CanonicalForm test= 1;
1842    for (int i= 0; i < factors.length(); i++)
1843    {
1844      if (i == 0)
1845        test *= mod (bufFactors [i], power (x, j));
1846      else
1847        test *= bufFactors[i];
1848    }
1849    test= mod (test, power (x, j));
1850    test= mod (test, MOD);
1851    CanonicalForm test2= mod (F, power (x, j - 1)) - mod (test, power (x, j-1));
1852    DEBOUTLN (cerr, "test= " << test2);
1853#endif
1854
1855  if (degree (Pi [factors.length() - 2], x) > 0)
1856    E= F[j] - Pi [factors.length() - 2] [j];
1857  else
1858    E= F[j];
1859
1860  CFArray buf= CFArray (diophant.length());
1861
1862  // actual lifting
1863  CFList diophantine2= diophantine (diophant, factors, products, MOD, E);
1864
1865  int k= 0;
1866  for (CFListIterator i= diophantine2; k < factors.length(); k++, i++)
1867  {
1868    buf[k]= i.getItem();
1869    bufFactors[k] += xToJ*i.getItem();
1870  }
1871
1872  // update Pi [0]
1873  int degBuf0= degree (bufFactors[0], x);
1874  int degBuf1= degree (bufFactors[1], x);
1875  if (degBuf0 > 0 && degBuf1 > 0)
1876  {
1877    M (j + 1, 1)= mulMod (bufFactors[0] [j], bufFactors[1] [j], MOD);
1878    if (j + 2 <= M.rows())
1879      M (j + 2, 1)= mulMod (bufFactors[0] [j + 1], bufFactors[1] [j + 1], MOD);
1880  }
1881  CanonicalForm uIZeroJ;
1882
1883    if (degBuf0 > 0 && degBuf1 > 0)
1884      uIZeroJ= mulMod (bufFactors[0] [0], buf[1], MOD) + 
1885               mulMod (bufFactors[1] [0], buf[0], MOD);
1886    else if (degBuf0 > 0)
1887      uIZeroJ= mulMod (buf[0], bufFactors[1], MOD);
1888    else if (degBuf1 > 0)
1889      uIZeroJ= mulMod (bufFactors[0], buf[1], MOD);
1890    else
1891      uIZeroJ= 0;
1892    Pi [0] += xToJ*uIZeroJ; 
1893
1894  CFArray tmp= CFArray (factors.length() - 1);
1895  for (k= 0; k < factors.length() - 1; k++)
1896    tmp[k]= 0;
1897  CFIterator one, two;
1898  one= bufFactors [0];
1899  two= bufFactors [1];
1900  if (degBuf0 > 0 && degBuf1 > 0)
1901  {
1902    while (one.exp() > j) one++;
1903    while (two.exp() > j) two++;
1904    for (k= 1; k <= (int) ceil (j/2.0); k++)
1905    { 
1906      if (k != j - k + 1)
1907      {
1908        if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
1909        {
1910          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()), 
1911                    (bufFactors[1] [k] + two.coeff()), MOD) - M (k + 1, 1) - 
1912                    M (j - k + 2, 1);
1913          one++;
1914          two++;
1915        }
1916        else if (one.exp() == j - k + 1)
1917        {
1918          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()), 
1919                    bufFactors[1] [k], MOD) - M (k + 1, 1);
1920          one++;
1921        }
1922        else if (two.exp() == j - k + 1)
1923        {
1924          tmp[0] += mulMod (bufFactors[0] [k], (bufFactors[1] [k] + 
1925                    two.coeff()), MOD) - M (k + 1, 1);
1926          two++;
1927        }
1928      }
1929      else
1930      {
1931        tmp[0] += M (k + 1, 1);
1932      }
1933    }
1934   
1935    if (j + 2 <= M.rows())
1936    {
1937      if (degBuf0 >= j + 1 && degBuf1 >= j + 1)
1938        tmp [0] += mulMod ((bufFactors [0] [j + 1]+ bufFactors [0] [0]), 
1939                           (bufFactors [1] [j + 1] + bufFactors [1] [0]), MOD)
1940                   - M(1,1) - M (j + 2,1);
1941      else if (degBuf0 >= j + 1)
1942        tmp[0] += mulMod (bufFactors [0] [j+1], bufFactors [1] [0], MOD);
1943      else if (degBuf1 >= j + 1)
1944        tmp[0] += mulMod (bufFactors [0] [0], bufFactors [1] [j + 1], MOD);
1945    }
1946  }
1947  Pi [0] += tmp[0]*xToJ*F.mvar();
1948
1949  // update Pi [l]
1950  int degPi, degBuf;
1951  for (int l= 1; l < factors.length() - 1; l++) 
1952  {
1953    degPi= degree (Pi [l - 1], x);
1954    degBuf= degree (bufFactors[l + 1], x);
1955    if (degPi > 0 && degBuf > 0)
1956      M (j + 1, l + 1)= mulMod (Pi [l - 1] [j], bufFactors[l + 1] [j], MOD); 
1957    if (j == 1)
1958    {
1959      if (degPi > 0 && degBuf > 0)
1960        Pi [l] += xToJ*(mulMod ((Pi [l - 1] [0] + Pi [l - 1] [j]), 
1961                  (bufFactors[l + 1] [0] + buf[l + 1]), MOD) - M (j + 1, l +1)- 
1962                  M (1, l + 1));
1963      else if (degPi > 0)
1964        Pi [l] += xToJ*(mulMod (Pi [l - 1] [j], bufFactors[l + 1], MOD));
1965      else if (degBuf > 0)
1966        Pi [l] += xToJ*(mulMod (Pi [l - 1], buf[l + 1], MOD));
1967    }
1968    else
1969    {
1970      if (degPi > 0 && degBuf > 0)
1971      {
1972        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
1973        uIZeroJ += mulMod (Pi [l - 1] [0], buf [l + 1], MOD); 
1974      }
1975      else if (degPi > 0)
1976        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1], MOD);
1977      else if (degBuf > 0)
1978      {
1979        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
1980        uIZeroJ += mulMod (Pi [l - 1], buf[l + 1], MOD);
1981      }
1982      Pi[l] += xToJ*uIZeroJ;
1983    }
1984    one= bufFactors [l + 1];
1985    two= Pi [l - 1];
1986    if (two.exp() == j + 1)
1987    {
1988      if (degBuf > 0 && degPi > 0)
1989      {
1990          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1][0], MOD);
1991          two++;
1992      }
1993      else if (degPi > 0)
1994      {     
1995          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1], MOD);
1996          two++;
1997      } 
1998    }
1999    if (degBuf > 0 && degPi > 0) 
2000    {
2001      for (k= 1; k <= (int) ceil (j/2.0); k++)
2002      { 
2003        if (k != j - k + 1)
2004        {
2005          if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
2006          {
2007            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()), 
2008                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1) - 
2009                      M (j - k + 2, l + 1);
2010            one++;
2011            two++;
2012          }
2013          else if (one.exp() == j - k + 1)
2014          {
2015            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()), 
2016                      Pi[l - 1] [k], MOD) - M (k + 1, l + 1);     
2017            one++;
2018          }
2019          else if (two.exp() == j - k + 1)
2020          {
2021            tmp[l] += mulMod (bufFactors[l + 1] [k], 
2022                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1);
2023            two++;
2024          }
2025        }
2026        else
2027          tmp[l] += M (k + 1, l + 1);
2028      } 
2029    } 
2030    Pi[l] += tmp[l]*xToJ*F.mvar();
2031  }
2032
2033  return;
2034}
2035
2036CFList
2037henselLift23 (const CFList& eval, const CFList& factors, const int* l, CFList&
2038              diophant, CFArray& Pi, CFMatrix& M)
2039{
2040  CFList buf= factors;
2041  int k= 0;
2042  int liftBoundBivar= l[k];
2043  diophant= biDiophantine (eval.getFirst(), buf, liftBoundBivar);
2044  CFList MOD;
2045  MOD.append (power (Variable (2), liftBoundBivar));
2046  CFArray bufFactors= CFArray (factors.length());
2047  k= 0;
2048  CFListIterator j= eval;
2049  j++;
2050  buf.removeFirst();
2051  buf.insert (LC (j.getItem(), 1));
2052  for (CFListIterator i= buf; i.hasItem(); i++, k++)
2053    bufFactors[k]= i.getItem();
2054  Pi= CFArray (factors.length() - 1);
2055  CFListIterator i= buf;
2056  i++;
2057  Variable y= j.getItem().mvar();
2058  Pi [0]= mulMod (i.getItem(), mod (buf.getFirst(), y), MOD);
2059  M (1, 1)= Pi [0];
2060  k= 1;
2061  if (i.hasItem())
2062    i++;
2063  for (; i.hasItem(); i++, k++) 
2064  {
2065    Pi [k]= mulMod (Pi [k - 1], i.getItem(), MOD);
2066    M (1, k + 1)= Pi [k];
2067  }
2068
2069  for (int d= 1; d < l[1]; d++)
2070    henselStep (j.getItem(), buf, bufFactors, diophant, M, Pi, d, MOD);
2071  CFList result;
2072  for (k= 1; k < factors.length(); k++)
2073    result.append (bufFactors[k]);
2074  return result;
2075} 
2076
2077void 
2078henselLiftResume (const CanonicalForm& F, CFList& factors, int start, int end, 
2079                  CFArray& Pi, const CFList& diophant, CFMatrix& M, 
2080                  const CFList& MOD)
2081{
2082  CFArray bufFactors= CFArray (factors.length());
2083  int i= 0;
2084  CanonicalForm xToStart= power (F.mvar(), start);
2085  for (CFListIterator k= factors; k.hasItem(); k++, i++)
2086  {
2087    if (i == 0)
2088      bufFactors[i]= mod (k.getItem(), xToStart);
2089    else
2090      bufFactors[i]= k.getItem();
2091  }
2092  for (i= start; i < end; i++)
2093    henselStep (F, factors, bufFactors, diophant, M, Pi, i, MOD); 
2094 
2095  CFListIterator k= factors;
2096  for (i= 0; i < factors.length(); k++, i++)
2097    k.getItem()= bufFactors [i];
2098  factors.removeFirst();
2099  return; 
2100} 
2101
2102CFList
2103henselLift (const CFList& F, const CFList& factors, const CFList& MOD, CFList&
2104            diophant, CFArray& Pi, CFMatrix& M, const int lOld, const int
2105            lNew)
2106{
2107  diophant= multiRecDiophantine (F.getFirst(), factors, diophant, MOD, lOld);
2108  int k= 0;
2109  CFArray bufFactors= CFArray (factors.length());
2110  for (CFListIterator i= factors; i.hasItem(); i++, k++)
2111  {
2112    if (k == 0)
2113      bufFactors[k]= LC (F.getLast(), 1);
2114    else
2115      bufFactors[k]= i.getItem();
2116  }
2117  CFList buf= factors;
2118  buf.removeFirst();
2119  buf.insert (LC (F.getLast(), 1));
2120  CFListIterator i= buf;
2121  i++;
2122  Variable y= F.getLast().mvar();
2123  Variable x= F.getFirst().mvar();
2124  CanonicalForm xToLOld= power (x, lOld);
2125  Pi [0]= mod (Pi[0], xToLOld);
2126  M (1, 1)= Pi [0];
2127  k= 1;
2128  if (i.hasItem())
2129    i++;
2130  for (; i.hasItem(); i++, k++) 
2131  {
2132    Pi [k]= mod (Pi [k], xToLOld);
2133    M (1, k + 1)= Pi [k];
2134  }
2135
2136  for (int d= 1; d < lNew; d++)
2137    henselStep (F.getLast(), buf, bufFactors, diophant, M, Pi, d, MOD);
2138  CFList result;
2139  for (k= 1; k < factors.length(); k++)
2140    result.append (bufFactors[k]);
2141  return result;
2142}
2143
2144CFList
2145henselLift (const CFList& eval, const CFList& factors, const int* l, const int
2146            lLength, bool sort)
2147{
2148  CFList diophant; 
2149  CFList buf= factors; 
2150  buf.insert (LC (eval.getFirst(), 1));
2151  if (sort)
2152    sortList (buf, Variable (1));
2153  CFArray Pi;
2154  CFMatrix M= CFMatrix (l[1], factors.length());
2155  CFList result= henselLift23 (eval, buf, l, diophant, Pi, M);
2156  if (eval.length() == 2)
2157    return result;
2158  CFList MOD;
2159  for (int i= 0; i < 2; i++)
2160    MOD.append (power (Variable (i + 2), l[i]));
2161  CFListIterator j= eval;
2162  j++;
2163  CFList bufEval;
2164  bufEval.append (j.getItem());
2165  j++;
2166 
2167  for (int i= 2; i <= lLength && j.hasItem(); i++, j++)
2168  {
2169    result.insert (LC (bufEval.getFirst(), 1));
2170    bufEval.append (j.getItem());
2171    M= CFMatrix (l[i], factors.length());
2172    result= henselLift (bufEval, result, MOD, diophant, Pi, M, l[i - 1], l[i]);
2173    MOD.append (power (Variable (i + 2), l[i]));
2174    bufEval.removeFirst();
2175  }
2176  return result; 
2177}
2178
2179// wrt. Variable (1)
2180CanonicalForm replaceLC (const CanonicalForm& F, const CanonicalForm& c)
2181{
2182  if (degree (F, 1) <= 0)
2183   return c;
2184  else
2185  {
2186    CanonicalForm result= swapvar (F, Variable (F.level() + 1), Variable (1));
2187    result += (swapvar (c, Variable (F.level() + 1), Variable (1)) 
2188              - LC (result))*power (result.mvar(), degree (result));
2189    return swapvar (result, Variable (F.level() + 1), Variable (1));
2190  } 
2191}
2192
2193// so far only for two factor Hensel lifting
2194CFList
2195henselLift232 (const CFList& eval, const CFList& factors, const int* l, CFList&
2196              diophant, CFArray& Pi, CFMatrix& M, const CFList& LCs1, 
2197              const CFList& LCs2)
2198{
2199  CFList buf= factors;
2200  int k= 0;
2201  int liftBoundBivar= l[k];
2202  CFList bufbuf= factors;
2203  Variable v= Variable (2);
2204
2205  CFList MOD;
2206  MOD.append (power (Variable (2), liftBoundBivar));
2207  CFArray bufFactors= CFArray (factors.length());
2208  k= 0;
2209  CFListIterator j= eval;
2210  j++;
2211  CFListIterator iter1= LCs1;
2212  CFListIterator iter2= LCs2;
2213  iter1++;
2214  iter2++;
2215  bufFactors[0]= replaceLC (buf.getFirst(), iter1.getItem());
2216  bufFactors[1]= replaceLC (buf.getLast(), iter2.getItem());
2217
2218  CFListIterator i= buf;
2219  i++;
2220  Variable y= j.getItem().mvar();
2221  if (y.level() != 3)
2222    y= Variable (3);
2223
2224  Pi[0]= mod (Pi[0], power (v, liftBoundBivar));
2225  M (1, 1)= Pi[0];
2226  if (degree (bufFactors[0], y) > 0 && degree (bufFactors [1], y) > 0)
2227    Pi [0] += (mulMod (bufFactors [0] [1], bufFactors[1] [0], MOD) + 
2228                        mulMod (bufFactors [0] [0], bufFactors [1] [1], MOD))*y;
2229  else if (degree (bufFactors[0], y) > 0)
2230    Pi [0] += mulMod (bufFactors [0] [1], bufFactors[1], MOD)*y;
2231  else if (degree (bufFactors[1], y) > 0)
2232    Pi [0] += mulMod (bufFactors [0], bufFactors[1] [1], MOD)*y;
2233 
2234  CFList products;
2235  for (int i= 0; i < bufFactors.size(); i++)
2236  {
2237    if (degree (bufFactors[i], y) > 0)
2238      products.append (M (1, 1)/bufFactors[i] [0]);
2239    else
2240      products.append (M (1, 1)/bufFactors[i]);
2241  }
2242 
2243  for (int d= 1; d < l[1]; d++)
2244    henselStep2 (j.getItem(), buf, bufFactors, diophant, M, Pi, products, d, MOD);
2245  CFList result;
2246  for (k= 0; k < factors.length(); k++)
2247    result.append (bufFactors[k]);
2248  return result;
2249} 
2250
2251
2252CFList
2253henselLift2 (const CFList& F, const CFList& factors, const CFList& MOD, CFList&
2254            diophant, CFArray& Pi, CFMatrix& M, const int lOld, const int
2255            lNew, const CFList& LCs1, const CFList& LCs2)
2256{
2257  int k= 0;
2258  CFArray bufFactors= CFArray (factors.length());
2259  bufFactors[0]= replaceLC (factors.getFirst(), LCs1.getLast());
2260  bufFactors[1]= replaceLC (factors.getLast(), LCs2.getLast());
2261  CFList buf= factors;
2262  Variable y= F.getLast().mvar();
2263  Variable x= F.getFirst().mvar();
2264  CanonicalForm xToLOld= power (x, lOld);
2265  Pi [0]= mod (Pi[0], xToLOld);
2266  M (1, 1)= Pi [0];
2267
2268  if (degree (bufFactors[0], y) > 0 && degree (bufFactors [1], y) > 0)
2269    Pi [0] += (mulMod (bufFactors [0] [1], bufFactors[1] [0], MOD) + 
2270                        mulMod (bufFactors [0] [0], bufFactors [1] [1], MOD))*y;
2271  else if (degree (bufFactors[0], y) > 0)
2272    Pi [0] += mulMod (bufFactors [0] [1], bufFactors[1], MOD)*y;
2273  else if (degree (bufFactors[1], y) > 0)
2274    Pi [0] += mulMod (bufFactors [0], bufFactors[1] [1], MOD)*y;
2275 
2276  CFList products;
2277  for (int i= 0; i < bufFactors.size(); i++)
2278  {
2279    if (degree (bufFactors[i], y) > 0)
2280    {
2281      ASSERT (fdivides (bufFactors[i] [0], M (1, 1)), "expected exact division");
2282      products.append (M (1, 1)/bufFactors[i] [0]);
2283    }
2284    else
2285    {
2286      ASSERT (fdivides (bufFactors[i], M (1, 1)), "expected exact division");
2287      products.append (M (1, 1)/bufFactors[i]);
2288    }
2289  }
2290 
2291  for (int d= 1; d < lNew; d++)
2292    henselStep2 (F.getLast(), buf, bufFactors, diophant, M, Pi, products, d, MOD);
2293  CFList result;
2294  for (k= 0; k < factors.length(); k++)
2295    result.append (bufFactors[k]);
2296  return result;
2297}
2298
2299// so far only for two! factor Hensel lifting
2300CFList
2301henselLift2 (const CFList& eval, const CFList& factors, const int* l, const int
2302             lLength, bool sort, const CFList& LCs1, const CFList& LCs2, 
2303             const CFArray& Pi, const CFList& diophant)
2304{
2305  CFList bufDiophant= diophant;
2306  CFList buf= factors;
2307  if (sort)
2308    sortList (buf, Variable (1));
2309  CFArray bufPi= Pi;
2310  CFMatrix M= CFMatrix (l[1], factors.length());
2311  CFList result= henselLift232 (eval, buf, l, bufDiophant, bufPi, M, LCs1, LCs2);
2312  if (eval.length() == 2)
2313    return result;
2314  CFList MOD;
2315  for (int i= 0; i < 2; i++)
2316    MOD.append (power (Variable (i + 2), l[i]));
2317  CFListIterator j= eval;
2318  j++;
2319  CFList bufEval;
2320  bufEval.append (j.getItem());
2321  j++;
2322  CFListIterator jj= LCs1;
2323  CFListIterator jjj= LCs2;
2324  CFList bufLCs1, bufLCs2;
2325  jj++, jjj++;
2326  bufLCs1.append (jj.getItem());
2327  bufLCs2.append (jjj.getItem());
2328  jj++, jjj++;
2329 
2330  for (int i= 2; i <= lLength && j.hasItem(); i++, j++, jj++, jjj++)
2331  {
2332    bufEval.append (j.getItem());
2333    bufLCs1.append (jj.getItem());
2334    bufLCs2.append (jjj.getItem());
2335    M= CFMatrix (l[i], factors.length());
2336    result= henselLift2 (bufEval, result, MOD, bufDiophant, bufPi, M, l[i - 1], 
2337                         l[i], bufLCs1, bufLCs2);
2338    MOD.append (power (Variable (i + 2), l[i]));
2339    bufEval.removeFirst();
2340    bufLCs1.removeFirst();
2341    bufLCs2.removeFirst();
2342  }
2343  return result;
2344}
2345
2346#endif
2347/* HAVE_NTL */
2348
Note: See TracBrowser for help on using the repository browser.