source: git/factory/facHensel.cc @ c9b1d66

spielwiese
Last change on this file since c9b1d66 was c9b1d66, checked in by Martin Lee <martinlee84@…>, 13 years ago
added division with remainder via Newton inversion git-svn-id: file:///usr/local/Singular/svn/trunk@13774 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 65.4 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.exp() > j) one++;
1769    while (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    if (j + 2 <= M.rows())
1799    {
1800      if (degBuf0 >= j + 1 && degBuf1 >= j + 1)
1801        tmp [0] += mulNTL ((bufFactors [0] [j + 1]+ bufFactors [0] [0]),
1802                           (bufFactors [1] [j + 1] + bufFactors [1] [0]))
1803                           - M(1,1) - M (j + 2,1);
1804      else if (degBuf0 >= j + 1)
1805        tmp[0] += mulNTL (bufFactors [0] [j+1], bufFactors [1] [0]);
1806      else if (degBuf1 >= j + 1)
1807        tmp[0] += mulNTL (bufFactors [0] [0], bufFactors [1] [j + 1]);
1808    }
1809  }
1810  Pi [0] += tmp[0]*xToJ*F.mvar();
1811
1812  /*// update Pi [l]
1813  int degPi, degBuf;
1814  for (int l= 1; l < factors.length() - 1; l++)
1815  {
1816    degPi= degree (Pi [l - 1], x);
1817    degBuf= degree (bufFactors[l + 1], x);
1818    if (degPi > 0 && degBuf > 0)
1819      M (j + 1, l + 1)= mulNTL (Pi [l - 1] [j], bufFactors[l + 1] [j]);
1820    if (j == 1)
1821    {
1822      if (degPi > 0 && degBuf > 0)
1823        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [0] + Pi [l - 1] [j],
1824                  bufFactors[l + 1] [0] + buf[l + 1]) - M (j + 1, l +1) -
1825                  M (1, l + 1));
1826      else if (degPi > 0)
1827        Pi [l] += xToJ*(mulNTL (Pi [l - 1] [j], bufFactors[l + 1]));
1828      else if (degBuf > 0)
1829        Pi [l] += xToJ*(mulNTL (Pi [l - 1], buf[l + 1]));
1830    }
1831    else
1832    {
1833      if (degPi > 0 && degBuf > 0)
1834      {
1835        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
1836        uIZeroJ += mulNTL (Pi [l - 1] [0], buf [l + 1]);
1837      }
1838      else if (degPi > 0)
1839        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1]);
1840      else if (degBuf > 0)
1841      {
1842        uIZeroJ= mulNTL (uIZeroJ, bufFactors [l + 1] [0]);
1843        uIZeroJ += mulNTL (Pi [l - 1], buf[l + 1]);
1844      }
1845      Pi[l] += xToJ*uIZeroJ;
1846    }
1847    one= bufFactors [l + 1];
1848    two= Pi [l - 1];
1849    if (two.exp() == j + 1)
1850    {
1851      if (degBuf > 0 && degPi > 0)
1852      {
1853          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1][0]);
1854          two++;
1855      }
1856      else if (degPi > 0)
1857      {
1858          tmp[l] += mulNTL (two.coeff(), bufFactors[l + 1]);
1859          two++;
1860      }
1861    }
1862    if (degBuf > 0 && degPi > 0)
1863    {
1864      for (k= 1; k <= (int) ceil (j/2.0); k++)
1865      {
1866        if (k != j - k + 1)
1867        {
1868          if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
1869          {
1870            tmp[l] += mulNTL ((bufFactors[l + 1][k]+one.coeff()),(Pi[l-1] [k] +
1871                        two.coeff())) - M (k + 1, l + 1) - M (j - k + 2, l + 1);
1872            one++;
1873            two++;
1874          }
1875          else if (one.exp() == j - k + 1)
1876          {
1877            tmp[l] += mulNTL ((bufFactors[l+1][k]+one.coeff()),Pi[l - 1] [k]) -
1878                        M (k + 1, l + 1);
1879            one++;
1880          }
1881          else if (two.exp() == j - k + 1)
1882          {
1883            tmp[l] += mulNTL (bufFactors[l+1][k],(Pi[l-1] [k] + two.coeff())) -
1884                      M (k + 1, l + 1);
1885            two++;
1886          }
1887        }
1888        else
1889          tmp[l] += M (k + 1, l + 1);
1890      }
1891    }
1892    Pi[l] += tmp[l]*xToJ*F.mvar();
1893  }*/
1894  return;
1895}
1896
1897void
1898henselLift122 (const CanonicalForm& F, CFList& factors, int l, CFArray& Pi,
1899              CFList& diophant, CFMatrix& M, const CFArray& LCs, bool sort)
1900{
1901  if (sort)
1902    sortList (factors, Variable (1));
1903  Pi= CFArray (factors.length() - 2);
1904  CFList bufFactors2= factors;
1905  bufFactors2.removeFirst();
1906  diophant.removeFirst();
1907  CFListIterator iter= diophant;
1908  CanonicalForm s,t;
1909  extgcd (bufFactors2.getFirst(), bufFactors2.getLast(), s, t);
1910  diophant= CFList();
1911  diophant.append (t);
1912  diophant.append (s);
1913  DEBOUTLN (cerr, "diophant= " << diophant);
1914
1915  CFArray bufFactors= CFArray (bufFactors2.length());
1916  int i= 0;
1917  for (CFListIterator k= bufFactors2; k.hasItem(); i++, k++)
1918    bufFactors[i]= replaceLc (k.getItem(), LCs [i]);
1919
1920  Variable x= F.mvar();
1921  if (degree (bufFactors[0], x) > 0 && degree (bufFactors [1], x) > 0)
1922  {
1923    M (1, 1)= mulNTL (bufFactors [0] [0], bufFactors[1] [0]);
1924    Pi [0]= M (1, 1) + (mulNTL (bufFactors [0] [1], bufFactors[1] [0]) +
1925                        mulNTL (bufFactors [0] [0], bufFactors [1] [1]))*x;
1926  }
1927  else if (degree (bufFactors[0], x) > 0)
1928  {
1929    M (1, 1)= mulNTL (bufFactors [0] [0], bufFactors[1]);
1930    Pi [0]= M (1, 1) +
1931            mulNTL (bufFactors [0] [1], bufFactors[1])*x;
1932  }
1933  else if (degree (bufFactors[1], x) > 0)
1934  {
1935    M (1, 1)= mulNTL (bufFactors [0], bufFactors[1] [0]);
1936    Pi [0]= M (1, 1) +
1937            mulNTL (bufFactors [0], bufFactors[1] [1])*x;
1938  }
1939  else
1940  {
1941    M (1, 1)= mulNTL (bufFactors [0], bufFactors[1]);
1942    Pi [0]= M (1, 1);
1943  }
1944
1945  for (i= 1; i < l; i++)
1946    henselStep122 (F, bufFactors2, bufFactors, diophant, M, Pi, i, LCs);
1947
1948  factors= CFList();
1949  for (i= 0; i < bufFactors.size(); i++)
1950    factors.append (bufFactors[i]);
1951  return;
1952}
1953
1954/// solve \f$ E=sum_{i= 1}^{r}{\sigma_{i}prod_{j=1, j\neq i}^{r}{f_{i}}}\f$
1955/// mod M, products contains \f$ prod_{j=1, j\neq i}^{r}{f_{i}}} \f$
1956static inline
1957CFList
1958diophantine (const CFList& recResult, const CFList& factors, 
1959             const CFList& products, const CFList& M, const CanonicalForm& E)
1960{
1961  if (M.isEmpty())
1962  {
1963    CFList result;
1964    CFListIterator j= factors;
1965    CanonicalForm buf;
1966    for (CFListIterator i= recResult; i.hasItem(); i++, j++)
1967    {
1968      ASSERT (E.isUnivariate() || E.inCoeffDomain(),
1969              "constant or univariate poly expected");
1970      ASSERT (i.getItem().isUnivariate() || i.getItem().inCoeffDomain(),
1971              "constant or univariate poly expected");
1972      ASSERT (j.getItem().isUnivariate() || j.getItem().inCoeffDomain(),
1973              "constant or univariate poly expected");
1974      buf= mulNTL (E, i.getItem());
1975      result.append (modNTL (buf, j.getItem()));
1976    }
1977    return result;
1978  }
1979  Variable y= M.getLast().mvar();
1980  CFList bufFactors= factors;
1981  for (CFListIterator i= bufFactors; i.hasItem(); i++)
1982    i.getItem()= mod (i.getItem(), y);
1983  CFList bufProducts= products;
1984  for (CFListIterator i= bufProducts; i.hasItem(); i++)
1985    i.getItem()= mod (i.getItem(), y);
1986  CFList buf= M;
1987  buf.removeLast();
1988  CanonicalForm bufE= mod (E, y);
1989  CFList recDiophantine= diophantine (recResult, bufFactors, bufProducts, buf,
1990                                      bufE);
1991
1992  CanonicalForm e= E;
1993  CFListIterator j= products;
1994  for (CFListIterator i= recDiophantine; i.hasItem(); i++, j++)
1995    e -= mulMod (i.getItem(), j.getItem(), M);
1996
1997  CFList result= recDiophantine;
1998  int d= degree (M.getLast());
1999  CanonicalForm coeffE;
2000  for (int i= 1; i < d; i++)
2001  {
2002    if (degree (e, y) > 0)
2003      coeffE= e[i];
2004    else
2005      coeffE= 0;
2006    if (!coeffE.isZero())
2007    {
2008      CFListIterator k= result;
2009      recDiophantine= diophantine (recResult, bufFactors, bufProducts, buf,
2010                                   coeffE);
2011      CFListIterator l= products;
2012      for (j= recDiophantine; j.hasItem(); j++, k++, l++)
2013      {
2014        k.getItem() += j.getItem()*power (y, i);
2015        e -= mulMod (j.getItem()*power (y, i), l.getItem(), M);
2016      }
2017    }
2018    if (e.isZero())
2019      break;
2020  }
2021  return result;
2022}
2023
2024// non monic case
2025static inline
2026CFList
2027multiRecDiophantine2 (const CanonicalForm& F, const CFList& factors,
2028                     const CFList& recResult, const CFList& M, const int d)
2029{
2030  Variable y= F.mvar();
2031  CFList result;
2032  CFListIterator i;
2033  CanonicalForm e= 1;
2034  CFListIterator j= factors;
2035  CFList p;
2036  CFArray bufFactors= CFArray (factors.length());
2037  CanonicalForm yToD= power (y, d);
2038  int k= 0;
2039  for (CFListIterator i= factors; i.hasItem(); i++, k++)
2040    bufFactors [k]= i.getItem();
2041  CanonicalForm b;
2042  CFList buf= M;
2043  buf.removeLast();
2044  buf.append (yToD);
2045  for (k= 0; k < factors.length(); k++) //TODO compute b's faster
2046  {
2047    b= 1;
2048    if (fdivides (bufFactors[k], F))
2049      b= F/bufFactors[k];
2050    else 
2051    {
2052      for (int l= 0; l < factors.length(); l++)
2053      {
2054        if (l == k)
2055          continue;
2056        else
2057        {
2058          b= mulMod (b, bufFactors[l], buf);
2059        }
2060      }
2061    }
2062    p.append (b);
2063  }
2064  j= p;
2065  for (CFListIterator i= recResult; i.hasItem(); i++, j++)
2066    e -= mulMod (i.getItem(), j.getItem(), M);
2067  if (e.isZero())
2068    return recResult;
2069  CanonicalForm coeffE;
2070  result= recResult;
2071  CanonicalForm g;
2072  buf.removeLast();
2073  for (int i= 1; i < d; i++)
2074  {
2075    if (degree (e, y) > 0)
2076      coeffE= e[i];
2077    else
2078      coeffE= 0;
2079    if (!coeffE.isZero())
2080    {
2081      CFListIterator k= result;
2082      CFListIterator l= p;
2083      j= recResult;
2084      int ii= 0;
2085      CanonicalForm dummy;
2086      CFList recDiophantine;
2087      CFList buf2, buf3;
2088      buf2= factors;
2089      buf3= p;
2090      for (CFListIterator iii= buf2; iii.hasItem(); iii++)
2091        iii.getItem()= mod (iii.getItem(), y);
2092      for (CFListIterator iii= buf3; iii.hasItem(); iii++)
2093        iii.getItem()= mod (iii.getItem(), y);
2094      recDiophantine= diophantine (recResult, buf2, buf3, buf, coeffE);
2095      CFListIterator iter= recDiophantine;
2096      for (; j.hasItem(); j++, k++, l++, ii++, iter++)
2097      {
2098        k.getItem() += iter.getItem()*power (y, i);
2099        e -= mulMod (iter.getItem()*power (y, i), l.getItem(), M);
2100      }
2101    }
2102    if (e.isZero())
2103      break;
2104  }
2105
2106#ifdef DEBUGOUTPUT
2107    CanonicalForm test= 0;
2108    j= p; 
2109    for (CFListIterator i= result; i.hasItem(); i++, j++)
2110      test += mod (i.getItem()*j.getItem(), power (y, d));
2111    DEBOUTLN (cerr, "test= " << test);
2112#endif
2113  return result;
2114}
2115
2116// so far only tested for two! factor Hensel lifting
2117static inline
2118void
2119henselStep2 (const CanonicalForm& F, const CFList& factors, CFArray& bufFactors,
2120            const CFList& diophant, CFMatrix& M, CFArray& Pi,
2121            const CFList& products, int j, const CFList& MOD)
2122{
2123  CanonicalForm E;
2124  CanonicalForm xToJ= power (F.mvar(), j);
2125  Variable x= F.mvar();
2126
2127  // compute the error
2128#ifdef DEBUGOUTPUT
2129    CanonicalForm test= 1;
2130    for (int i= 0; i < factors.length(); i++)
2131    {
2132      if (i == 0)
2133        test *= mod (bufFactors [i], power (x, j));
2134      else
2135        test *= bufFactors[i];
2136    }
2137    test= mod (test, power (x, j));
2138    test= mod (test, MOD);
2139    CanonicalForm test2= mod (F, power (x, j - 1)) - mod (test, power (x, j-1));
2140    DEBOUTLN (cerr, "test= " << test2);
2141#endif
2142
2143  if (degree (Pi [factors.length() - 2], x) > 0)
2144    E= F[j] - Pi [factors.length() - 2] [j];
2145  else
2146    E= F[j];
2147
2148  CFArray buf= CFArray (diophant.length());
2149
2150  // actual lifting
2151  CFList diophantine2= diophantine (diophant, factors, products, MOD, E);
2152
2153  int k= 0;
2154  for (CFListIterator i= diophantine2; k < factors.length(); k++, i++)
2155  {
2156    buf[k]= i.getItem();
2157    bufFactors[k] += xToJ*i.getItem();
2158  }
2159
2160  // update Pi [0]
2161  int degBuf0= degree (bufFactors[0], x);
2162  int degBuf1= degree (bufFactors[1], x);
2163  if (degBuf0 > 0 && degBuf1 > 0)
2164  {
2165    M (j + 1, 1)= mulMod (bufFactors[0] [j], bufFactors[1] [j], MOD);
2166    if (j + 2 <= M.rows())
2167      M (j + 2, 1)= mulMod (bufFactors[0] [j + 1], bufFactors[1] [j + 1], MOD);
2168  }
2169  CanonicalForm uIZeroJ;
2170
2171    if (degBuf0 > 0 && degBuf1 > 0)
2172      uIZeroJ= mulMod (bufFactors[0] [0], buf[1], MOD) +
2173               mulMod (bufFactors[1] [0], buf[0], MOD);
2174    else if (degBuf0 > 0)
2175      uIZeroJ= mulMod (buf[0], bufFactors[1], MOD);
2176    else if (degBuf1 > 0)
2177      uIZeroJ= mulMod (bufFactors[0], buf[1], MOD);
2178    else
2179      uIZeroJ= 0;
2180    Pi [0] += xToJ*uIZeroJ; 
2181
2182  CFArray tmp= CFArray (factors.length() - 1);
2183  for (k= 0; k < factors.length() - 1; k++)
2184    tmp[k]= 0;
2185  CFIterator one, two;
2186  one= bufFactors [0];
2187  two= bufFactors [1];
2188  if (degBuf0 > 0 && degBuf1 > 0)
2189  {
2190    while (one.exp() > j) one++;
2191    while (two.exp() > j) two++;
2192    for (k= 1; k <= (int) ceil (j/2.0); k++)
2193    {
2194      if (k != j - k + 1)
2195      {
2196        if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
2197        {
2198          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()),
2199                    (bufFactors[1] [k] + two.coeff()), MOD) - M (k + 1, 1) -
2200                    M (j - k + 2, 1);
2201          one++;
2202          two++;
2203        }
2204        else if (one.exp() == j - k + 1)
2205        {
2206          tmp[0] += mulMod ((bufFactors[0] [k] + one.coeff()),
2207                    bufFactors[1] [k], MOD) - M (k + 1, 1);
2208          one++;
2209        }
2210        else if (two.exp() == j - k + 1)
2211        {
2212          tmp[0] += mulMod (bufFactors[0] [k], (bufFactors[1] [k] +
2213                    two.coeff()), MOD) - M (k + 1, 1);
2214          two++;
2215        }
2216      }
2217      else
2218      {
2219        tmp[0] += M (k + 1, 1);
2220      }
2221    }
2222
2223    if (j + 2 <= M.rows())
2224    {
2225      if (degBuf0 >= j + 1 && degBuf1 >= j + 1)
2226        tmp [0] += mulMod ((bufFactors [0] [j + 1]+ bufFactors [0] [0]),
2227                           (bufFactors [1] [j + 1] + bufFactors [1] [0]), MOD)
2228                   - M(1,1) - M (j + 2,1);
2229      else if (degBuf0 >= j + 1)
2230        tmp[0] += mulMod (bufFactors [0] [j+1], bufFactors [1] [0], MOD);
2231      else if (degBuf1 >= j + 1)
2232        tmp[0] += mulMod (bufFactors [0] [0], bufFactors [1] [j + 1], MOD);
2233    }
2234  }
2235  Pi [0] += tmp[0]*xToJ*F.mvar();
2236
2237  // update Pi [l]
2238  int degPi, degBuf;
2239  for (int l= 1; l < factors.length() - 1; l++)
2240  {
2241    degPi= degree (Pi [l - 1], x);
2242    degBuf= degree (bufFactors[l + 1], x);
2243    if (degPi > 0 && degBuf > 0)
2244      M (j + 1, l + 1)= mulMod (Pi [l - 1] [j], bufFactors[l + 1] [j], MOD);
2245    if (j == 1)
2246    {
2247      if (degPi > 0 && degBuf > 0)
2248        Pi [l] += xToJ*(mulMod ((Pi [l - 1] [0] + Pi [l - 1] [j]),
2249                  (bufFactors[l + 1] [0] + buf[l + 1]), MOD) - M (j + 1, l +1)-
2250                  M (1, l + 1));
2251      else if (degPi > 0)
2252        Pi [l] += xToJ*(mulMod (Pi [l - 1] [j], bufFactors[l + 1], MOD));
2253      else if (degBuf > 0)
2254        Pi [l] += xToJ*(mulMod (Pi [l - 1], buf[l + 1], MOD));
2255    }
2256    else
2257    {
2258      if (degPi > 0 && degBuf > 0)
2259      {
2260        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
2261        uIZeroJ += mulMod (Pi [l - 1] [0], buf [l + 1], MOD);
2262      }
2263      else if (degPi > 0)
2264        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1], MOD);
2265      else if (degBuf > 0)
2266      {
2267        uIZeroJ= mulMod (uIZeroJ, bufFactors [l + 1] [0], MOD);
2268        uIZeroJ += mulMod (Pi [l - 1], buf[l + 1], MOD);
2269      }
2270      Pi[l] += xToJ*uIZeroJ;
2271    }
2272    one= bufFactors [l + 1];
2273    two= Pi [l - 1];
2274    if (two.exp() == j + 1)
2275    {
2276      if (degBuf > 0 && degPi > 0)
2277      {
2278          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1][0], MOD);
2279          two++;
2280      }
2281      else if (degPi > 0)
2282      {
2283          tmp[l] += mulMod (two.coeff(), bufFactors[l + 1], MOD);
2284          two++;
2285      }
2286    }
2287    if (degBuf > 0 && degPi > 0)
2288    {
2289      for (k= 1; k <= (int) ceil (j/2.0); k++)
2290      {
2291        if (k != j - k + 1)
2292        {
2293          if (one.exp() == j - k + 1 && two.exp() == j - k + 1)
2294          {
2295            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()),
2296                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1) -
2297                      M (j - k + 2, l + 1);
2298            one++;
2299            two++;
2300          }
2301          else if (one.exp() == j - k + 1)
2302          {
2303            tmp[l] += mulMod ((bufFactors[l + 1] [k] + one.coeff()),
2304                      Pi[l - 1] [k], MOD) - M (k + 1, l + 1);
2305            one++;
2306          }
2307          else if (two.exp() == j - k + 1)
2308          {
2309            tmp[l] += mulMod (bufFactors[l + 1] [k],
2310                      (Pi[l - 1] [k] + two.coeff()), MOD) - M (k + 1, l + 1);
2311            two++;
2312          }
2313        }
2314        else
2315          tmp[l] += M (k + 1, l + 1);
2316      }
2317    }
2318    Pi[l] += tmp[l]*xToJ*F.mvar();
2319  }
2320
2321  return;
2322}
2323
2324// wrt. Variable (1)
2325CanonicalForm replaceLC (const CanonicalForm& F, const CanonicalForm& c)
2326{
2327  if (degree (F, 1) <= 0)
2328   return c;
2329  else
2330  {
2331    CanonicalForm result= swapvar (F, Variable (F.level() + 1), Variable (1));
2332    result += (swapvar (c, Variable (F.level() + 1), Variable (1))
2333              - LC (result))*power (result.mvar(), degree (result));
2334    return swapvar (result, Variable (F.level() + 1), Variable (1));
2335  }
2336}
2337
2338// so far only for two factor Hensel lifting
2339CFList
2340henselLift232 (const CFList& eval, const CFList& factors, int* l, CFList&
2341              diophant, CFArray& Pi, CFMatrix& M, const CFList& LCs1,
2342              const CFList& LCs2)
2343{
2344  CFList buf= factors;
2345  int k= 0;
2346  int liftBoundBivar= l[k];
2347  CFList bufbuf= factors;
2348  Variable v= Variable (2);
2349
2350  CFList MOD;
2351  MOD.append (power (Variable (2), liftBoundBivar));
2352  CFArray bufFactors= CFArray (factors.length());
2353  k= 0;
2354  CFListIterator j= eval;
2355  j++;
2356  CFListIterator iter1= LCs1;
2357  CFListIterator iter2= LCs2;
2358  iter1++;
2359  iter2++;
2360  bufFactors[0]= replaceLC (buf.getFirst(), iter1.getItem());
2361  bufFactors[1]= replaceLC (buf.getLast(), iter2.getItem());
2362
2363  CFListIterator i= buf;
2364  i++;
2365  Variable y= j.getItem().mvar();
2366  if (y.level() != 3)
2367    y= Variable (3);
2368
2369  Pi[0]= mod (Pi[0], power (v, liftBoundBivar));
2370  M (1, 1)= Pi[0];
2371  if (degree (bufFactors[0], y) > 0 && degree (bufFactors [1], y) > 0)
2372    Pi [0] += (mulMod (bufFactors [0] [1], bufFactors[1] [0], MOD) +
2373                        mulMod (bufFactors [0] [0], bufFactors [1] [1], MOD))*y;
2374  else if (degree (bufFactors[0], y) > 0)
2375    Pi [0] += mulMod (bufFactors [0] [1], bufFactors[1], MOD)*y;
2376  else if (degree (bufFactors[1], y) > 0)
2377    Pi [0] += mulMod (bufFactors [0], bufFactors[1] [1], MOD)*y;
2378
2379  CFList products;
2380  for (int i= 0; i < bufFactors.size(); i++)
2381  {
2382    if (degree (bufFactors[i], y) > 0)
2383      products.append (M (1, 1)/bufFactors[i] [0]);
2384    else
2385      products.append (M (1, 1)/bufFactors[i]);
2386  }
2387
2388  for (int d= 1; d < l[1]; d++)
2389    henselStep2 (j.getItem(), buf, bufFactors, diophant, M, Pi, products, d, MOD);
2390  CFList result;
2391  for (k= 0; k < factors.length(); k++)
2392    result.append (bufFactors[k]);
2393  return result;
2394}
2395
2396
2397CFList
2398henselLift2 (const CFList& F, const CFList& factors, const CFList& MOD, CFList&
2399            diophant, CFArray& Pi, CFMatrix& M, const int lOld, int&
2400            lNew, const CFList& LCs1, const CFList& LCs2)
2401{
2402  int k= 0;
2403  CFArray bufFactors= CFArray (factors.length());
2404  bufFactors[0]= replaceLC (factors.getFirst(), LCs1.getLast());
2405  bufFactors[1]= replaceLC (factors.getLast(), LCs2.getLast());
2406  CFList buf= factors;
2407  Variable y= F.getLast().mvar();
2408  Variable x= F.getFirst().mvar();
2409  CanonicalForm xToLOld= power (x, lOld);
2410  Pi [0]= mod (Pi[0], xToLOld);
2411  M (1, 1)= Pi [0];
2412
2413  if (degree (bufFactors[0], y) > 0 && degree (bufFactors [1], y) > 0)
2414    Pi [0] += (mulMod (bufFactors [0] [1], bufFactors[1] [0], MOD) + 
2415                        mulMod (bufFactors [0] [0], bufFactors [1] [1], MOD))*y;
2416  else if (degree (bufFactors[0], y) > 0)
2417    Pi [0] += mulMod (bufFactors [0] [1], bufFactors[1], MOD)*y;
2418  else if (degree (bufFactors[1], y) > 0)
2419    Pi [0] += mulMod (bufFactors [0], bufFactors[1] [1], MOD)*y;
2420
2421  CFList products;
2422  for (int i= 0; i < bufFactors.size(); i++)
2423  {
2424    if (degree (bufFactors[i], y) > 0)
2425    {
2426      ASSERT (fdivides (bufFactors[i][0], M (1, 1)), "expected exact division");
2427      products.append (M (1, 1)/bufFactors[i] [0]);
2428    }
2429    else
2430    {
2431      ASSERT (fdivides (bufFactors[i], M (1, 1)), "expected exact division");
2432      products.append (M (1, 1)/bufFactors[i]);
2433    }
2434  }
2435
2436  for (int d= 1; d < lNew; d++)
2437    henselStep2 (F.getLast(),buf,bufFactors, diophant, M, Pi, products, d, MOD);
2438
2439  CFList result;
2440  for (k= 0; k < factors.length(); k++)
2441    result.append (bufFactors[k]);
2442  return result;
2443}
2444
2445// so far only for two! factor Hensel lifting
2446CFList
2447henselLift2 (const CFList& eval, const CFList& factors, int* l, const int
2448             lLength, bool sort, const CFList& LCs1, const CFList& LCs2,
2449             const CFArray& Pi, const CFList& diophant)
2450{
2451  CFList bufDiophant= diophant;
2452  CFList buf= factors;
2453  if (sort)
2454    sortList (buf, Variable (1));
2455  CFArray bufPi= Pi;
2456  CFMatrix M= CFMatrix (l[1], factors.length());
2457  CFList result= henselLift232(eval, buf, l, bufDiophant, bufPi, M, LCs1, LCs2);
2458  if (eval.length() == 2)
2459    return result;
2460  CFList MOD;
2461  for (int i= 0; i < 2; i++)
2462    MOD.append (power (Variable (i + 2), l[i]));
2463  CFListIterator j= eval;
2464  j++;
2465  CFList bufEval;
2466  bufEval.append (j.getItem());
2467  j++;
2468  CFListIterator jj= LCs1;
2469  CFListIterator jjj= LCs2;
2470  CFList bufLCs1, bufLCs2;
2471  jj++, jjj++;
2472  bufLCs1.append (jj.getItem());
2473  bufLCs2.append (jjj.getItem());
2474  jj++, jjj++;
2475
2476  for (int i= 2; i < lLength && j.hasItem(); i++, j++, jj++, jjj++)
2477  {
2478    bufEval.append (j.getItem());
2479    bufLCs1.append (jj.getItem());
2480    bufLCs2.append (jjj.getItem());
2481    M= CFMatrix (l[i], factors.length());
2482    result= henselLift2 (bufEval, result, MOD, bufDiophant, bufPi, M, l[i - 1],
2483                         l[i], bufLCs1, bufLCs2);
2484    MOD.append (power (Variable (i + 2), l[i]));
2485    bufEval.removeFirst();
2486    bufLCs1.removeFirst();
2487    bufLCs2.removeFirst();
2488  }
2489  return result;
2490}
2491
2492#endif
2493/* HAVE_NTL */
2494
Note: See TracBrowser for help on using the repository browser.