source: git/factory/facHensel.cc @ c1b9927

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