source: git/factory/facHensel.cc @ 6e2ef0e

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