source: git/factory/facHensel.cc @ 1b8e048

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