source: git/factory/facFqFactorize.cc @ 9a12097

spielwiese
Last change on this file since 9a12097 was 9a12097, checked in by Martin Lee <martinlee84@…>, 12 years ago
chg: use NTL zz_p* instead of ZZ_p*, deleted unneccessary includes
  • Property mode set to 100644
File size: 75.6 KB
Line 
1/*****************************************************************************\
2 * Computer Algebra System SINGULAR
3\*****************************************************************************/
4/** @file facFqFactorize.cc
5 *
6 * This file implements functions for factoring a multivariate polynomial over
7 * a finite field.
8 *
9 * ABSTRACT: "Efficient Multivariate Factorization over Finite Fields" by
10 * L. Bernardin & M. Monagon. Precomputation of leading coefficients is
11 * described in "Sparse Hensel lifting" by E. Kaltofen
12 *
13 * @author Martin Lee
14 *
15 * @internal @version \$Id$
16 *
17 **/
18/*****************************************************************************/
19
20#include "config.h"
21
22#include "cf_assert.h"
23#include "debug.h"
24#include "timing.h"
25
26#include "facFqFactorizeUtil.h"
27#include "facFqFactorize.h"
28#include "cf_random.h"
29#include "facHensel.h"
30#include "cf_gcd_smallp.h"
31#include "cf_map_ext.h"
32#include "algext.h"
33#include "facSparseHensel.h"
34#include "facMul.h"
35
36#ifdef HAVE_NTL
37#include "NTLconvert.h"
38
39TIMING_DEFINE_PRINT(fac_bi_factorizer)
40TIMING_DEFINE_PRINT(fac_hensel_lift)
41TIMING_DEFINE_PRINT(fac_factor_recombination)
42
43static inline
44CanonicalForm
45listGCD (const CFList& L);
46
47static inline
48CanonicalForm
49myContent (const CanonicalForm& F)
50{
51  Variable x= Variable (1);
52  CanonicalForm G= swapvar (F, F.mvar(), x);
53  CFList L;
54  for (CFIterator i= G; i.hasTerms(); i++)
55    L.append (i.coeff());
56  if (L.length() == 2)
57    return swapvar (gcd (L.getFirst(), L.getLast()), F.mvar(), x);
58  if (L.length() == 1)
59    return LC (F, x);
60  return swapvar (listGCD (L), F.mvar(), x);
61}
62
63static inline
64CanonicalForm
65listGCD (const CFList& L)
66{
67  if (L.length() == 1)
68    return L.getFirst();
69  if (L.length() == 2)
70    return gcd (L.getFirst(), L.getLast());
71  else
72  {
73    CFList lHi, lLo;
74    CanonicalForm resultHi, resultLo;
75    int length= L.length()/2;
76    int j= 0;
77    for (CFListIterator i= L; j < length; i++, j++)
78      lHi.append (i.getItem());
79    lLo= Difference (L, lHi);
80    resultHi= listGCD (lHi);
81    resultLo= listGCD (lLo);
82    if (resultHi.isOne() || resultLo.isOne())
83      return 1;
84    return gcd (resultHi, resultLo);
85  }
86}
87
88static inline
89CanonicalForm
90myContent (const CanonicalForm& F, const Variable& x)
91{
92  if (degree (F, x) <= 0)
93    return 1;
94  CanonicalForm G= F;
95  bool swap= false;
96  if (x != F.mvar())
97  {
98    swap= true;
99    G= swapvar (F, x, F.mvar());
100  }
101  CFList L;
102  Variable alpha;
103  for (CFIterator i= G; i.hasTerms(); i++)
104    L.append (i.coeff());
105  if (L.length() == 2)
106  {
107    if (swap)
108      return swapvar (gcd (L.getFirst(), L.getLast()), F.mvar(), x);
109    else
110      return gcd (L.getFirst(), L.getLast());
111  }
112  if (L.length() == 1)
113  {
114    return LC (F, x);
115  }
116  if (swap)
117    return swapvar (listGCD (L), F.mvar(), x);
118  else
119    return listGCD (L);
120}
121
122CanonicalForm myCompress (const CanonicalForm& F, CFMap& N)
123{
124  int n= F.level();
125  int * degsf= new int [n + 1];
126  int ** swap;
127  swap= new int* [n + 1];
128  for (int i= 0; i <= n; i++)
129  {
130    degsf[i]= 0;
131    swap [i]= new int [2];
132    swap [i] [0]= 0;
133    swap [i] [1]= 0;
134  }
135  int i= 1;
136  n= 1;
137  degsf= degrees (F, degsf);
138
139  CanonicalForm result= F;
140  while ( i <= F.level() )
141  {
142    while( degsf[i] == 0 ) i++;
143    swap[n][0]= i;
144    swap[n][1]= degsf[i];
145    if (i != n)
146      result= swapvar (result, Variable (n), Variable(i));
147    n++; i++;
148  }
149
150  int buf1, buf2;
151  n--;
152
153  for (i= 1; i < n; i++)
154  {
155    for (int j= 1; j < n - i + 1; j++)
156    {
157      if (swap[j][1] < swap[j + 1][1])
158      {
159        buf1= swap [j + 1] [0];
160        buf2= swap [j + 1] [1];
161        swap[j + 1] [0]= swap[j] [0];
162        swap[j + 1] [1]= swap[j] [1];
163        swap[j][0]= buf1;
164        swap[j][1]= buf2;
165        result= swapvar (result, Variable (j + 1), Variable (j));
166      }
167    }
168  }
169
170  for (i= n; i > 0; i--)
171  {
172    if (i != swap[i] [0])
173      N.newpair (Variable (i), Variable (swap[i] [0]));
174  }
175
176  for (i= 0; i <= n; i++)
177    delete [] swap[i];
178  delete [] swap;
179
180  delete [] degsf;
181
182  return result;
183}
184
185CFList
186extFactorRecombination (const CFList& factors, const CanonicalForm& F,
187                        const CFList& M, const ExtensionInfo& info,
188                        const CFList& evaluation)
189{
190  Variable alpha= info.getAlpha();
191  Variable beta= info.getBeta();
192  CanonicalForm gamma= info.getGamma();
193  CanonicalForm delta= info.getDelta();
194  int k= info.getGFDegree();
195  CFList source, dest;
196  if (factors.length() == 1)
197  {
198    CanonicalForm buf= reverseShift (F, evaluation);
199    return CFList (mapDown (buf, info, source, dest));
200  }
201  if (factors.length() < 1)
202    return CFList();
203
204  int degMipoBeta= 1;
205  if (!k && beta.level() != 1)
206    degMipoBeta= degree (getMipo (beta));
207
208  CFList T, S;
209  T= factors;
210
211  int s= 1;
212  CFList result;
213  CanonicalForm buf;
214
215  buf= F;
216
217  Variable x= Variable (1);
218  CanonicalForm g, LCBuf= LC (buf, x);
219  CanonicalForm buf2, quot;
220  int * v= new int [T.length()];
221  for (int i= 0; i < T.length(); i++)
222    v[i]= 0;
223  bool noSubset= false;
224  CFArray TT;
225  TT= copy (factors);
226  bool recombination= false;
227  bool trueFactor= false;
228  while (T.length() >= 2*s)
229  {
230    while (noSubset == false)
231    {
232      if (T.length() == s)
233      {
234        delete [] v;
235        if (recombination)
236        {
237          T.insert (LCBuf);
238          g= prodMod (T, M);
239          T.removeFirst();
240          result.append (g/myContent (g));
241          g= reverseShift (g, evaluation);
242          g /= Lc (g);
243          appendTestMapDown (result, g, info, source, dest);
244          return result;
245        }
246        else
247        {
248          buf= reverseShift (buf, evaluation);
249          return CFList (buf);
250        }
251      }
252
253      S= subset (v, s, TT, noSubset);
254      if (noSubset) break;
255
256      S.insert (LCBuf);
257      g= prodMod (S, M);
258      S.removeFirst();
259      g /= myContent (g);
260      if (fdivides (g, buf, quot))
261      {
262        buf2= reverseShift (g, evaluation);
263        buf2 /= Lc (buf2);
264        if (!k && beta == x)
265        {
266          if (degree (buf2, alpha) < degMipoBeta)
267          {
268            appendTestMapDown (result, buf2, info, source, dest);
269            buf= quot;
270            LCBuf= LC (buf, x);
271            recombination= true;
272            trueFactor= true;
273          }
274        }
275        else
276        {
277          if (!isInExtension (buf2, gamma, k, delta, source, dest))
278          {
279            appendTestMapDown (result, buf2, info, source, dest);
280            buf /= g;
281            LCBuf= LC (buf, x);
282            recombination= true;
283            trueFactor= true;
284          }
285        }
286
287        if (trueFactor)
288        {
289          T= Difference (T, S);
290
291          if (T.length() < 2*s || T.length() == s)
292          {
293            buf= reverseShift (buf, evaluation);
294            buf /= Lc (buf);
295            appendTestMapDown (result, buf, info, source, dest);
296            delete [] v;
297            return result;
298          }
299          trueFactor= false;
300          TT= copy (T);
301          indexUpdate (v, s, T.length(), noSubset);
302          if (noSubset) break;
303        }
304      }
305    }
306    s++;
307    if (T.length() < 2*s || T.length() == s)
308    {
309      buf= reverseShift (buf, evaluation);
310      appendTestMapDown (result, buf, info, source, dest);
311      delete [] v;
312      return result;
313    }
314    for (int i= 0; i < T.length(); i++)
315      v[i]= 0;
316    noSubset= false;
317  }
318  if (T.length() < 2*s)
319  {
320    buf= reverseShift (F, evaluation);
321    appendMapDown (result, buf, info, source, dest);
322  }
323
324  delete [] v;
325  return result;
326}
327
328CFList
329factorRecombination (const CanonicalForm& F, const CFList& factors,
330                     const CFList& M)
331{
332  if (factors.length() == 1)
333    return CFList(F);
334  if (factors.length() < 1)
335    return CFList();
336
337  CFList T, S;
338
339  T= factors;
340
341  int s= 1;
342  CFList result;
343  CanonicalForm LCBuf= LC (F, Variable (1));
344  CanonicalForm g, buf= F;
345  int * v= new int [T.length()];
346  for (int i= 0; i < T.length(); i++)
347    v[i]= 0;
348  bool noSubset= false;
349  CFArray TT;
350  TT= copy (factors);
351  Variable y= F.level() - 1;
352  bool recombination= false;
353  CanonicalForm h, quot;
354  while (T.length() >= 2*s)
355  {
356    while (noSubset == false)
357    {
358      if (T.length() == s)
359      {
360        delete [] v;
361        if (recombination)
362        {
363          T.insert (LC (buf));
364          g= prodMod (T, M);
365          result.append (g/myContent (g));
366          return result;
367        }
368        else
369          return CFList (F);
370      }
371      S= subset (v, s, TT, noSubset);
372      if (noSubset) break;
373      S.insert (LCBuf);
374      g= prodMod (S, M);
375      S.removeFirst();
376      g /= myContent (g);
377      if (fdivides (g, buf, quot))
378      {
379        recombination= true;
380        result.append (g);
381        buf= quot;
382        LCBuf= LC (buf, Variable(1));
383        T= Difference (T, S);
384        if (T.length() < 2*s || T.length() == s)
385        {
386          result.append (buf);
387          delete [] v;
388          return result;
389        }
390        TT= copy (T);
391        indexUpdate (v, s, T.length(), noSubset);
392        if (noSubset) break;
393      }
394    }
395    s++;
396    if (T.length() < 2*s || T.length() == s)
397    {
398      result.append (buf);
399      delete [] v;
400      return result;
401    }
402    for (int i= 0; i < T.length(); i++)
403      v[i]= 0;
404    noSubset= false;
405  }
406  if (T.length() < 2*s)
407    result.append (F);
408
409  delete [] v;
410  return result;
411}
412
413int
414liftBoundAdaption (const CanonicalForm& F, const CFList& factors, bool&
415                   success, const int deg, const CFList& MOD, const int bound)
416{
417  int adaptedLiftBound= 0;
418  CanonicalForm buf= F;
419  Variable y= F.mvar();
420  Variable x= Variable (1);
421  CanonicalForm LCBuf= LC (buf, x);
422  CanonicalForm g, quot;
423  CFList M= MOD;
424  M.append (power (y, deg));
425  int d= bound;
426  int e= 0;
427  int nBuf;
428  for (CFListIterator i= factors; i.hasItem(); i++)
429  {
430    g= mulMod (i.getItem(), LCBuf, M);
431    g /= myContent (g);
432    if (fdivides (g, buf, quot))
433    {
434      nBuf= degree (g, y) + degree (LC (g, 1), y);
435      d -= nBuf;
436      e= tmax (e, nBuf);
437      buf= quot;
438      LCBuf= LC (buf, x);
439    }
440  }
441  adaptedLiftBound= d;
442
443  if (adaptedLiftBound < deg)
444  {
445    if (adaptedLiftBound < degree (F) + 1)
446    {
447      if (d == 1)
448      {
449        if (e + 1 > deg)
450        {
451          adaptedLiftBound= deg;
452          success= false;
453        }
454        else
455        {
456          success= true;
457          if (e + 1 < degree (F) + 1)
458            adaptedLiftBound= deg;
459          else
460            adaptedLiftBound= e + 1;
461        }
462      }
463      else
464      {
465        success= true;
466        adaptedLiftBound= deg;
467      }
468    }
469    else
470    {
471      success= true;
472    }
473  }
474  return adaptedLiftBound;
475}
476
477int
478extLiftBoundAdaption (const CanonicalForm& F, const CFList& factors, bool&
479                      success, const ExtensionInfo& info, const CFList& eval,
480                      const int deg, const CFList& MOD, const int bound)
481{
482  Variable alpha= info.getAlpha();
483  Variable beta= info.getBeta();
484  CanonicalForm gamma= info.getGamma();
485  CanonicalForm delta= info.getDelta();
486  int k= info.getGFDegree();
487  int adaptedLiftBound= 0;
488  CanonicalForm buf= F;
489  Variable y= F.mvar();
490  Variable x= Variable (1);
491  CanonicalForm LCBuf= LC (buf, x);
492  CanonicalForm g, gg, quot;
493  CFList M= MOD;
494  M.append (power (y, deg));
495  adaptedLiftBound= 0;
496  int d= bound;
497  int e= 0;
498  int nBuf;
499  int degMipoBeta= 1;
500  if (!k && beta.level() != 1)
501    degMipoBeta= degree (getMipo (beta));
502
503  CFList source, dest;
504  for (CFListIterator i= factors; i.hasItem(); i++)
505  {
506    g= mulMod (i.getItem(), LCBuf, M);
507    g /= myContent (g);
508    if (fdivides (g, buf, quot))
509    {
510      gg= reverseShift (g, eval);
511      gg /= Lc (gg);
512      if (!k && beta == x)
513      {
514        if (degree (gg, alpha) < degMipoBeta)
515        {
516          buf= quot;
517          nBuf= degree (g, y) + degree (LC (g, x), y);
518          d -= nBuf;
519          e= tmax (e, nBuf);
520          LCBuf= LC (buf, x);
521        }
522      }
523      else
524      {
525        if (!isInExtension (gg, gamma, k, delta, source, dest))
526        {
527          buf= quot;
528          nBuf= degree (g, y) + degree (LC (g, x), y);
529          d -= nBuf;
530          e= tmax (e, nBuf);
531          LCBuf= LC (buf, x);
532        }
533      }
534    }
535  }
536  adaptedLiftBound= d;
537
538  if (adaptedLiftBound < deg)
539  {
540    if (adaptedLiftBound < degree (F) + 1)
541    {
542      if (d == 1)
543      {
544        if (e + 1 > deg)
545        {
546          adaptedLiftBound= deg;
547          success= false;
548        }
549        else
550        {
551          success= true;
552          if (e + 1 < degree (F) + 1)
553            adaptedLiftBound= deg;
554          else
555            adaptedLiftBound= e + 1;
556        }
557      }
558      else
559      {
560        success= true;
561        adaptedLiftBound= deg;
562      }
563    }
564    else
565    {
566      success= true;
567    }
568  }
569
570  return adaptedLiftBound;
571}
572
573CFList
574earlyFactorDetect (CanonicalForm& F, CFList& factors, int& adaptedLiftBound,
575                   bool& success, const int deg, const CFList& MOD,
576                   const int bound)
577{
578  CFList result;
579  CFList T= factors;
580  CanonicalForm buf= F;
581  Variable y= F.mvar();
582  Variable x= Variable (1);
583  CanonicalForm LCBuf= LC (buf, x);
584  CanonicalForm g, quot;
585  CFList M= MOD;
586  M.append (power (y, deg));
587  adaptedLiftBound= 0;
588  int d= bound;
589  int e= 0;
590  int nBuf;
591  for (CFListIterator i= factors; i.hasItem(); i++)
592  {
593    g= mulMod (i.getItem(), LCBuf, M);
594    g /= myContent (g);
595    if (fdivides (g, buf, quot))
596    {
597      result.append (g);
598      nBuf= degree (g, y) + degree (LC (g, x), y);
599      d -= nBuf;
600      e= tmax (e, nBuf);
601      buf= quot;
602      LCBuf= LC (buf, x);
603      T= Difference (T, CFList (i.getItem()));
604    }
605  }
606  adaptedLiftBound= d;
607
608  if (adaptedLiftBound < deg)
609  {
610    if (adaptedLiftBound < degree (F) + 1)
611    {
612      if (d == 1)
613        adaptedLiftBound= tmin (e + 1, deg);
614      else
615        adaptedLiftBound= deg;
616    }
617    factors= T;
618    F= buf;
619    success= true;
620  }
621  return result;
622}
623
624CFList
625extEarlyFactorDetect (CanonicalForm& F, CFList& factors, int& adaptedLiftBound,
626                      bool& success, const ExtensionInfo& info, const CFList&
627                      eval, const int deg, const CFList& MOD, const int bound)
628{
629  Variable alpha= info.getAlpha();
630  Variable beta= info.getBeta();
631  CanonicalForm gamma= info.getGamma();
632  CanonicalForm delta= info.getDelta();
633  int k= info.getGFDegree();
634  CFList result;
635  CFList T= factors;
636  CanonicalForm buf= F;
637  Variable y= F.mvar();
638  Variable x= Variable (1);
639  CanonicalForm LCBuf= LC (buf, x);
640  CanonicalForm g, gg, quot;
641  CFList M= MOD;
642  M.append (power (y, deg));
643  adaptedLiftBound= 0;
644  int d= bound;
645  int e= 0;
646  int nBuf;
647  CFList source, dest;
648
649  int degMipoBeta= 1;
650  if (!k && beta.level() != 1)
651    degMipoBeta= degree (getMipo (beta));
652
653  for (CFListIterator i= factors; i.hasItem(); i++)
654  {
655    g= mulMod (i.getItem(), LCBuf, M);
656    g /= myContent (g);
657    if (fdivides (g, buf, quot))
658    {
659      gg= reverseShift (g, eval);
660      gg /= Lc (gg);
661      if (!k && beta == x)
662      {
663        if (degree (gg, alpha) < degMipoBeta)
664        {
665          appendTestMapDown (result, gg, info, source, dest);
666          buf= quot;
667          nBuf= degree (g, y) + degree (LC (g, x), y);
668          d -= nBuf;
669          e= tmax (e, nBuf);
670          LCBuf= LC (buf, x);
671          T= Difference (T, CFList (i.getItem()));
672        }
673      }
674      else
675      {
676        if (!isInExtension (gg, gamma, k, delta, source, dest))
677        {
678          appendTestMapDown (result, gg, info, source, dest);
679          buf= quot;
680          nBuf= degree (g, y) + degree (LC (g, x), y);
681          d -= nBuf;
682          e= tmax (e, nBuf);
683          LCBuf= LC (buf, x);
684          T= Difference (T, CFList (i.getItem()));
685         }
686      }
687    }
688  }
689  adaptedLiftBound= d;
690
691  if (adaptedLiftBound < deg)
692  {
693    if (adaptedLiftBound < degree (F) + 1)
694    {
695      if (d == 1)
696        adaptedLiftBound= tmin (e + 1, deg);
697      else
698        adaptedLiftBound= deg;
699    }
700    success= true;
701    factors= T;
702    F= buf;
703  }
704  return result;
705}
706
707CFList
708evalPoints (const CanonicalForm& F, CFList & eval, const Variable& alpha,
709            CFList& list, const bool& GF, bool& fail)
710{
711  int k= F.level() - 1;
712  Variable x= Variable (1);
713  CFList result;
714  FFRandom genFF;
715  GFRandom genGF;
716  int p= getCharacteristic ();
717  double bound;
718  if (alpha != x)
719  {
720    bound= pow ((double) p, (double) degree (getMipo(alpha)));
721    bound= pow ((double) bound, (double) k);
722  }
723  else if (GF)
724  {
725    bound= pow ((double) p, (double) getGFDegree());
726    bound= pow ((double) bound, (double) k);
727  }
728  else
729    bound= pow ((double) p, (double) k);
730
731  CanonicalForm random;
732  CanonicalForm deriv_x, gcd_deriv;
733  do
734  {
735    random= 0;
736    // possible overflow if list.length() does not fit into a int
737    if (list.length() >= bound)
738    {
739      fail= true;
740      break;
741    }
742    for (int i= 0; i < k; i++)
743    {
744      if (list.isEmpty())
745        result.append (0);
746      else if (GF)
747      {
748        result.append (genGF.generate());
749        random += result.getLast()*power (x, i);
750      }
751      else if (alpha.level() != 1)
752      {
753        AlgExtRandomF genAlgExt (alpha);
754        result.append (genAlgExt.generate());
755        random += result.getLast()*power (x, i);
756      }
757      else
758      {
759        result.append (genFF.generate());
760        random += result.getLast()*power (x, i);
761      }
762    }
763    if (find (list, random))
764    {
765      result= CFList();
766      continue;
767    }
768    int l= F.level();
769    eval.insert (F);
770    bool bad= false;
771    for (CFListIterator i= result; i.hasItem(); i++, l--)
772    {
773      eval.insert (eval.getFirst()(i.getItem(), l));
774      if (degree (eval.getFirst(), l - 1) != degree (F, l - 1))
775      {
776        if (!find (list, random))
777          list.append (random);
778        result= CFList();
779        eval= CFList();
780        bad= true;
781        break;
782      }
783    }
784
785    if (bad)
786      continue;
787
788    if (degree (eval.getFirst()) != degree (F, 1))
789    {
790      if (!find (list, random))
791        list.append (random);
792      result= CFList();
793      eval= CFList();
794      continue;
795    }
796
797    deriv_x= deriv (eval.getFirst(), x);
798    gcd_deriv= gcd (eval.getFirst(), deriv_x);
799    if (degree (gcd_deriv) > 0)
800    {
801      if (!find (list, random))
802        list.append (random);
803      result= CFList();
804      eval= CFList();
805      continue;
806    }
807    CFListIterator i= eval;
808    i++;
809    CanonicalForm contentx= content (i.getItem(), x);
810    if (degree (contentx) > 0)
811    {
812      if (!find (list, random))
813        list.append (random);
814      result= CFList();
815      eval= CFList();
816      continue;
817    }
818
819    if (list.length() >= bound)
820    {
821      fail= true;
822      break;
823    }
824  } while (find (list, random));
825
826  if (!eval.isEmpty())
827    eval.removeFirst();
828
829  return result;
830}
831
832static inline
833int newMainVariableSearch (CanonicalForm& A, CFList& Aeval, CFList&
834                           evaluation, const Variable& alpha, const int lev,
835                           CanonicalForm& g
836                          )
837{
838  Variable x= Variable (1);
839  CanonicalForm derivI, buf;
840  bool GF= (CFFactory::gettype() == GaloisFieldDomain);
841  int swapLevel= 0;
842  CFList list;
843  bool fail= false;
844  buf= A;
845  Aeval= CFList();
846  evaluation= CFList();
847  for (int i= lev; i <= A.level(); i++)
848  {
849    derivI= deriv (buf, Variable (i));
850    if (!derivI.isZero())
851    {
852      g= gcd (buf, derivI);
853      if (degree (g) > 0)
854        return -1;
855
856      buf= swapvar (buf, x, Variable (i));
857      Aeval= CFList();
858      evaluation= CFList();
859      fail= false;
860      evaluation= evalPoints (buf, Aeval, alpha, list, GF, fail);
861      if (!fail)
862      {
863        A= buf;
864        swapLevel= i;
865        break;
866      }
867      else
868        buf= A;
869    }
870  }
871  return swapLevel;
872}
873
874CanonicalForm lcmContent (const CanonicalForm& A, CFList& contentAi)
875{
876  int i= A.level();
877  contentAi.append (myContent (A, i));
878  contentAi.append (myContent (A, i - 1));
879  CanonicalForm result= lcm (contentAi.getFirst(), contentAi.getLast());
880  for (i= i - 2; i > 0; i--)
881  {
882    contentAi.append (content (A, i));
883    result= lcm (result, contentAi.getLast());
884  }
885  return result;
886}
887
888CFList
889henselLiftAndEarly (CanonicalForm& A, CFList& MOD, int*& liftBounds, bool&
890                    earlySuccess, CFList& earlyFactors, const CFList& Aeval,
891                    const CFList& biFactors, const CFList& evaluation,
892                    const ExtensionInfo& info)
893{
894  bool extension= info.isInExtension();
895  CFList bufFactors= biFactors;
896  bufFactors.insert (LC (Aeval.getFirst(), 1));
897
898  sortList (bufFactors, Variable (1));
899
900  CFList diophant;
901  CFArray Pi;
902  int smallFactorDeg= 11; //tunable parameter
903  CFList result;
904  int adaptedLiftBound= 0;
905  int liftBound= liftBounds[1];
906
907  earlySuccess= false;
908  CFList earlyReconstFactors;
909  CFListIterator j= Aeval;
910  j++;
911  CanonicalForm buf= j.getItem();
912  CFMatrix Mat= CFMatrix (liftBound, bufFactors.length() - 1);
913  MOD= CFList (power (Variable (2), liftBounds[0]));
914  if (smallFactorDeg >= liftBound)
915  {
916    result= henselLift23 (Aeval, bufFactors, liftBounds, diophant, Pi, Mat);
917  }
918  else if (smallFactorDeg >= degree (buf) + 1)
919  {
920    liftBounds[1]= degree (buf) + 1;
921    result= henselLift23 (Aeval, bufFactors, liftBounds, diophant, Pi, Mat);
922    if (Aeval.length() == 2)
923    {
924      if (!extension)
925        earlyFactors= earlyFactorDetect
926                       (buf, result, adaptedLiftBound, earlySuccess,
927                        degree (buf) + 1, MOD, liftBound);
928      else
929        earlyFactors= extEarlyFactorDetect
930                       (buf, result, adaptedLiftBound, earlySuccess,
931                        info, evaluation, degree
932                        (buf) + 1, MOD, liftBound);
933    }
934    else
935    {
936      if (!extension)
937        adaptedLiftBound= liftBoundAdaption (buf, result, earlySuccess,
938                                             degree (buf) + 1, MOD, liftBound);
939      else
940        adaptedLiftBound= extLiftBoundAdaption (buf, result, earlySuccess, info,
941                                                evaluation, degree (buf) + 1,
942                                                MOD, liftBound);
943    }
944    if (!earlySuccess)
945    {
946      result.insert (LC (buf, 1));
947      liftBounds[1]= adaptedLiftBound;
948      liftBound= adaptedLiftBound;
949      henselLiftResume (buf, result, degree (buf) + 1, liftBound,
950                        Pi, diophant, Mat, MOD);
951    }
952    else
953      liftBounds[1]= adaptedLiftBound;
954  }
955  else if (smallFactorDeg < degree (buf) + 1)
956  {
957    liftBounds[1]= smallFactorDeg;
958    result= henselLift23 (Aeval, bufFactors, liftBounds, diophant, Pi, Mat);
959    if (Aeval.length() == 2)
960    {
961      if (!extension)
962        earlyFactors= earlyFactorDetect (buf, result, adaptedLiftBound,
963                                         earlySuccess, smallFactorDeg, MOD,
964                                         liftBound);
965      else
966        earlyFactors= extEarlyFactorDetect (buf, result, adaptedLiftBound,
967                                            earlySuccess, info, evaluation,
968                                            smallFactorDeg, MOD, liftBound);
969    }
970    else
971    {
972      if (!extension)
973        adaptedLiftBound= liftBoundAdaption (buf, result, earlySuccess,
974                                             smallFactorDeg, MOD, liftBound);
975      else
976        adaptedLiftBound= extLiftBoundAdaption (buf, result, earlySuccess, info,
977                                                evaluation, smallFactorDeg, MOD,
978                                                liftBound);
979    }
980
981    if (!earlySuccess)
982    {
983      result.insert (LC (buf, 1));
984      henselLiftResume (buf, result, smallFactorDeg, degree (buf) + 1,
985                        Pi, diophant, Mat, MOD);
986      if (Aeval.length() == 2)
987      {
988         if (!extension)
989           earlyFactors= earlyFactorDetect (buf, result, adaptedLiftBound,
990                                            earlySuccess, degree (buf) + 1,
991                                            MOD, liftBound);
992         else
993           earlyFactors= extEarlyFactorDetect (buf, result, adaptedLiftBound,
994                                               earlySuccess, info, evaluation,
995                                               degree (buf) + 1, MOD,
996                                               liftBound);
997      }
998      else
999      {
1000        if (!extension)
1001          adaptedLiftBound= liftBoundAdaption (buf, result, earlySuccess,
1002                                               degree (buf) + 1, MOD,liftBound);
1003        else
1004          adaptedLiftBound= extLiftBoundAdaption (buf, result, earlySuccess,
1005                                                  info, evaluation,
1006                                                  degree (buf) + 1, MOD,
1007                                                  liftBound);
1008      }
1009      if (!earlySuccess)
1010      {
1011        result.insert (LC (buf, 1));
1012        liftBounds[1]= adaptedLiftBound;
1013        liftBound= adaptedLiftBound;
1014        henselLiftResume (buf, result, degree (buf) + 1, liftBound,
1015                          Pi, diophant, Mat, MOD);
1016      }
1017      else
1018        liftBounds[1]= adaptedLiftBound;
1019    }
1020    else
1021      liftBounds[1]= adaptedLiftBound;
1022  }
1023
1024  MOD.append (power (Variable (3), liftBounds[1]));
1025
1026  if (Aeval.length() > 2)
1027  {
1028    CFListIterator j= Aeval;
1029    j++;
1030    CFList bufEval;
1031    bufEval.append (j.getItem());
1032    j++;
1033    int liftBoundsLength= Aeval.getLast().level() - 1;
1034    for (int i= 2; i <= liftBoundsLength && j.hasItem(); i++, j++)
1035    {
1036      earlySuccess= false;
1037      result.insert (LC (bufEval.getFirst(), 1));
1038      bufEval.append (j.getItem());
1039      liftBound= liftBounds[i];
1040      Mat= CFMatrix (liftBounds[i], result.length() - 1);
1041
1042      buf= j.getItem();
1043      if (smallFactorDeg >= liftBound)
1044        result= henselLift (bufEval, result, MOD, diophant, Pi, Mat,
1045                            liftBounds[i -  1], liftBounds[i]);
1046      else if (smallFactorDeg >= degree (buf) + 1)
1047      {
1048        result= henselLift (bufEval, result, MOD, diophant, Pi, Mat,
1049                            liftBounds[i -  1], degree (buf) + 1);
1050
1051        if (Aeval.length() == i + 1)
1052        {
1053          if (!extension)
1054            earlyFactors= earlyFactorDetect
1055                           (buf, result, adaptedLiftBound, earlySuccess,
1056                            degree (buf) + 1, MOD, liftBound);
1057          else
1058            earlyFactors= extEarlyFactorDetect
1059                           (buf, result, adaptedLiftBound, earlySuccess,
1060                            info, evaluation, degree (buf) + 1, MOD, liftBound);
1061        }
1062        else
1063        {
1064          if (!extension)
1065            adaptedLiftBound= liftBoundAdaption
1066                                (buf, result, earlySuccess, degree (buf)
1067                                 + 1,  MOD, liftBound);
1068          else
1069            adaptedLiftBound= extLiftBoundAdaption
1070                                (buf, result, earlySuccess, info, evaluation,
1071                                 degree (buf) + 1, MOD, liftBound);
1072        }
1073
1074        if (!earlySuccess)
1075        {
1076          result.insert (LC (buf, 1));
1077          liftBounds[i]= adaptedLiftBound;
1078          liftBound= adaptedLiftBound;
1079          henselLiftResume (buf, result, degree (buf) + 1, liftBound,
1080                            Pi, diophant, Mat, MOD);
1081        }
1082        else
1083        {
1084          liftBounds[i]= adaptedLiftBound;
1085        }
1086      }
1087      else if (smallFactorDeg < degree (buf) + 1)
1088      {
1089        result= henselLift (bufEval, result, MOD, diophant, Pi, Mat,
1090                            liftBounds[i -  1], smallFactorDeg);
1091
1092        if (Aeval.length() == i + 1)
1093        {
1094          if (!extension)
1095            earlyFactors= earlyFactorDetect
1096                           (buf, result, adaptedLiftBound, earlySuccess,
1097                            smallFactorDeg, MOD, liftBound);
1098          else
1099            earlyFactors= extEarlyFactorDetect
1100                           (buf, result, adaptedLiftBound, earlySuccess,
1101                            info, evaluation, smallFactorDeg, MOD, liftBound);
1102        }
1103        else
1104        {
1105          if (!extension)
1106            adaptedLiftBound= liftBoundAdaption
1107                                (buf, result, earlySuccess,
1108                                 smallFactorDeg, MOD, liftBound);
1109          else
1110            adaptedLiftBound= extLiftBoundAdaption
1111                                (buf, result, earlySuccess, info, evaluation,
1112                                 smallFactorDeg, MOD, liftBound);
1113        }
1114
1115        if (!earlySuccess)
1116        {
1117          result.insert (LC (buf, 1));
1118          henselLiftResume (buf, result, smallFactorDeg,
1119                            degree (buf) + 1, Pi, diophant, Mat, MOD);
1120          if (Aeval.length() == i + 1)
1121          {
1122            if (!extension)
1123              earlyFactors= earlyFactorDetect
1124                             (buf, result, adaptedLiftBound, earlySuccess,
1125                              degree (buf) +  1,  MOD, liftBound);
1126            else
1127              earlyFactors= extEarlyFactorDetect
1128                             (buf, result, adaptedLiftBound, earlySuccess,
1129                              info, evaluation, degree (buf) + 1, MOD,
1130                              liftBound);
1131          }
1132          else
1133          {
1134            if (!extension)
1135              adaptedLiftBound= liftBoundAdaption
1136                                  (buf, result, earlySuccess, degree
1137                                   (buf) +  1,  MOD, liftBound);
1138            else
1139              adaptedLiftBound= extLiftBoundAdaption
1140                                  (buf, result, earlySuccess, info, evaluation,
1141                                   degree (buf) + 1,  MOD, liftBound);
1142          }
1143
1144          if (!earlySuccess)
1145          {
1146            result.insert (LC (buf, 1));
1147            liftBounds[i]= adaptedLiftBound;
1148            liftBound= adaptedLiftBound;
1149            henselLiftResume (buf, result, degree (buf) + 1, liftBound,
1150                              Pi, diophant, Mat, MOD);
1151          }
1152          else
1153            liftBounds[i]= adaptedLiftBound;
1154        }
1155        else
1156          liftBounds[i]= adaptedLiftBound;
1157      }
1158      MOD.append (power (Variable (i + 2), liftBounds[i]));
1159      bufEval.removeFirst();
1160    }
1161    bufFactors= result;
1162  }
1163  else
1164    bufFactors= result;
1165
1166  if (earlySuccess)
1167    A= buf;
1168  return result;
1169}
1170
1171void
1172gcdFreeBasis (CFFList& factors1, CFFList& factors2)
1173{
1174  CanonicalForm g;
1175  int k= factors1.length();
1176  int l= factors2.length();
1177  int n= 1;
1178  int m;
1179  CFFListIterator j;
1180  for (CFFListIterator i= factors1; (n < k && i.hasItem()); i++, n++)
1181  {
1182    m= 1;
1183    for (j= factors2; (m < l && j.hasItem()); j++, m++)
1184    {
1185      g= gcd (i.getItem().factor(), j.getItem().factor());
1186      if (degree (g) > 0)
1187      {
1188        j.getItem()= CFFactor (j.getItem().factor()/g, j.getItem().exp());
1189        i.getItem()= CFFactor (i.getItem().factor()/g, i.getItem().exp());
1190        factors1.append (CFFactor (g, i.getItem().exp()));
1191        factors2.append (CFFactor (g, j.getItem().exp()));
1192      }
1193    }
1194  }
1195}
1196
1197CFList
1198distributeContent (const CFList& L, const CFList* differentSecondVarFactors,
1199                   int length
1200                  )
1201{
1202  CFList l= L;
1203  CanonicalForm content= l.getFirst();
1204
1205  if (content.inCoeffDomain())
1206    return l;
1207
1208  if (l.length() == 1)
1209  {
1210    CFList result;
1211    for (int i= 0; i < length; i++)
1212    {
1213      if (differentSecondVarFactors[i].isEmpty())
1214        continue;
1215      if (result.isEmpty())
1216      {
1217        result= differentSecondVarFactors[i];
1218        for (CFListIterator iter= result; iter.hasItem(); iter++)
1219          content /= iter.getItem();
1220      }
1221      else
1222      {
1223        CFListIterator iter1= result;
1224        for (CFListIterator iter2= differentSecondVarFactors[i]; iter2.hasItem();
1225             iter2++, iter1++)
1226        {
1227          iter1.getItem() *= iter2.getItem();
1228          content /= iter2.getItem();
1229        }
1230      }
1231    }
1232    result.insert (content);
1233    return result;
1234  }
1235
1236  Variable v;
1237  CFListIterator iter1;
1238  CanonicalForm tmp, g;
1239  for (int i= 0; i < length; i++)
1240  {
1241    if (differentSecondVarFactors[i].isEmpty())
1242      continue;
1243    iter1= l;
1244    iter1++;
1245
1246    v= Variable (i + 3);
1247    for (CFListIterator iter2= differentSecondVarFactors[i]; iter2.hasItem();
1248         iter2++, iter1++)
1249    {
1250      if (degree (iter2.getItem(),v) == degree (iter1.getItem(),v))
1251        continue;
1252      tmp= iter1.getItem();
1253      for (int j= tmp.level(); j > 1; j--)
1254      {
1255        if (j == i + 3)
1256          continue;
1257        tmp= tmp (0, j);
1258      }
1259      g= gcd (iter2.getItem(), content);
1260      if (degree (g) > 0)
1261      {
1262        if (!tmp.isZero())
1263          iter2.getItem() /= tmp;
1264        content /= g;
1265        iter1.getItem() *= g;
1266      }
1267    }
1268  }
1269
1270  l.removeFirst();
1271  l.insert (content);
1272  return l;
1273}
1274
1275CFList evaluateAtZero (const CanonicalForm& F)
1276{
1277  CFList result;
1278  CanonicalForm buf= F;
1279  result.insert (buf);
1280  for (int i= F.level(); i > 2; i--)
1281  {
1282    buf= buf (0, i);
1283    result.insert (buf);
1284  }
1285  return result;
1286}
1287
1288CFList evaluateAtEval (const CanonicalForm& F, const CFArray& eval)
1289{
1290  CFList result;
1291  CanonicalForm buf= F;
1292  result.insert (buf);
1293  int k= eval.size();
1294  for (int i= 1; i < k; i++)
1295  {
1296    buf= buf (eval[i], i + 2);
1297    result.insert (buf);
1298  }
1299  return result;
1300}
1301
1302CFList evaluateAtEval (const CanonicalForm& F, const CFList& evaluation, int l)
1303{
1304  CFList result;
1305  CanonicalForm buf= F;
1306  result.insert (buf);
1307  int k= evaluation.length() + l - 1;
1308  CFListIterator j= evaluation;
1309  for (int i= k; j.hasItem() && i > l; i--, j++)
1310  {
1311    if (F.level() < i)
1312      continue;
1313    buf= buf (j.getItem(), i);
1314    result.insert (buf);
1315  }
1316  return result;
1317}
1318
1319int
1320testFactors (const CanonicalForm& G, const CFList& uniFactors,
1321             const Variable& alpha, CanonicalForm& sqrfPartF, CFList& factors,
1322             CFFList*& bufSqrfFactors, CFList& evalSqrfPartF,
1323             const CFArray& evalPoint)
1324{
1325  CanonicalForm tmp;
1326  CFListIterator j;
1327  for (CFListIterator i= uniFactors; i.hasItem(); i++)
1328  {
1329    tmp= i.getItem();
1330    if (i.hasItem())
1331      i++;
1332    else
1333      break;
1334    for (j= i; j.hasItem(); j++)
1335    {
1336      if (tmp == j.getItem())
1337        return 0;
1338    }
1339  }
1340
1341  CanonicalForm F= G;
1342  CFFList sqrfFactorization= squarefreeFactorization (F, alpha);
1343
1344  sqrfPartF= 1;
1345  for (CFFListIterator i= sqrfFactorization; i.hasItem(); i++)
1346    sqrfPartF *= i.getItem().factor();
1347
1348  evalSqrfPartF= evaluateAtEval (sqrfPartF, evalPoint);
1349
1350  CanonicalForm test= evalSqrfPartF.getFirst() (evalPoint[0], 2);
1351
1352  if (degree (test) != degree (sqrfPartF, 1))
1353    return 0;
1354
1355  CFFList sqrfFactors;
1356  CFList tmp2;
1357  int k= 0;
1358  factors= uniFactors;
1359  CFFListIterator iter;
1360  for (CFListIterator i= factors; i.hasItem(); i++, k++)
1361  {
1362    tmp= 1;
1363    sqrfFactors= squarefreeFactorization (i.getItem(), alpha);
1364
1365    for (iter= sqrfFactors; iter.hasItem(); iter++)
1366    {
1367      tmp2.append (iter.getItem().factor());
1368      tmp *= iter.getItem().factor();
1369    }
1370    i.getItem()= tmp/Lc(tmp);
1371    bufSqrfFactors [k]= sqrfFactors;
1372  }
1373
1374  for (int i= 0; i < factors.length() - 1; i++)
1375  {
1376    for (k= i + 1; k < factors.length(); k++)
1377    {
1378      gcdFreeBasis (bufSqrfFactors [i], bufSqrfFactors[k]);
1379    }
1380  }
1381
1382  factors= CFList();
1383  for (int i= 0; i < uniFactors.length(); i++)
1384  {
1385    if (i == 0)
1386    {
1387      for (iter= bufSqrfFactors [i]; iter.hasItem(); iter++)
1388      {
1389        if (iter.getItem().factor().inCoeffDomain())
1390          continue;
1391        iter.getItem()= CFFactor (iter.getItem().factor()/
1392                                  Lc (iter.getItem().factor()),
1393                                  iter.getItem().exp());
1394        factors.append (iter.getItem().factor());
1395      }
1396    }
1397    else
1398    {
1399      for (iter= bufSqrfFactors [i]; iter.hasItem(); iter++)
1400      {
1401        if (iter.getItem().factor().inCoeffDomain())
1402          continue;
1403        iter.getItem()= CFFactor (iter.getItem().factor()/
1404                                  Lc (iter.getItem().factor()),
1405                                  iter.getItem().exp());
1406        if (!find (factors, iter.getItem().factor()))
1407          factors.append (iter.getItem().factor());
1408      }
1409    }
1410  }
1411
1412  test= prod (factors);
1413  tmp= evalSqrfPartF.getFirst() (evalPoint[0],2);
1414  if (test/Lc (test) != tmp/Lc (tmp))
1415    return 0;
1416  else
1417    return 1;
1418}
1419
1420CFList
1421precomputeLeadingCoeff (const CanonicalForm& LCF, const CFList& LCFFactors,
1422                        const Variable& alpha, const CFList& evaluation,
1423                        CFList* & differentSecondVarLCs, int lSecondVarLCs,
1424                        Variable& y
1425                       )
1426{
1427  y= Variable (1);
1428  if (LCF.inCoeffDomain())
1429  {
1430    CFList result;
1431    for (int i= 1; i <= LCFFactors.length() + 1; i++)
1432      result.append (1);
1433    return result;
1434  }
1435
1436  CFMap N;
1437  CanonicalForm F= compress (LCF, N);
1438  if (LCF.isUnivariate())
1439  {
1440    CFList result;
1441    int LCFLevel= LCF.level();
1442    bool found= false;
1443    if (LCFLevel == 2)
1444    {
1445    //bivariate leading coefficients are already the true leading coefficients
1446      result= LCFFactors;
1447      found= true;
1448    }
1449    else
1450    {
1451      CFListIterator j;
1452      for (int i= 0; i < lSecondVarLCs; i++)
1453      {
1454        for (j= differentSecondVarLCs[i]; j.hasItem(); j++)
1455        {
1456          if (j.getItem().level() == LCFLevel)
1457          {
1458            found= true;
1459            break;
1460          }
1461        }
1462        if (found)
1463        {
1464          result= differentSecondVarLCs [i];
1465          break;
1466        }
1467      }
1468      if (!found)
1469        result= LCFFactors;
1470    }
1471    if (found)
1472      result.insert (Lc (LCF));
1473    else
1474      result.append (LCF);
1475    return result;
1476  }
1477
1478  CFList factors= LCFFactors;
1479
1480  CFMap dummy;
1481  for (CFListIterator i= factors; i.hasItem(); i++)
1482    i.getItem()= compress (i.getItem(), dummy);
1483
1484  CanonicalForm sqrfPartF;
1485  CFFList * bufSqrfFactors= new CFFList [factors.length()];
1486  CFList evalSqrfPartF, bufFactors;
1487  CFArray evalPoint= CFArray (evaluation.length() - 1);
1488  CFListIterator iter= evaluation;
1489  for (int i= evaluation.length() - 2; i > -1; i--, iter++)
1490    evalPoint[i]= iter.getItem();
1491
1492  int pass= testFactors (F, factors, alpha, sqrfPartF,
1493                         bufFactors, bufSqrfFactors, evalSqrfPartF, evalPoint);
1494
1495  bool foundDifferent= false;
1496  Variable z, x= y;
1497  int j= 0;
1498  if (!pass)
1499  {
1500    int lev= 0;
1501    // LCF is non-constant here
1502    for (int i= 1; i <= LCF.level(); i++)
1503    {
1504      if(degree (LCF, i) > 0)
1505      {
1506        lev= i - 1;
1507        break;
1508      }
1509    }
1510    CFList bufBufFactors;
1511    CanonicalForm bufF, swap;
1512    CFArray buf;
1513    for (int i= 0; i < lSecondVarLCs; i++)
1514    {
1515      if (!differentSecondVarLCs [i].isEmpty())
1516      {
1517        bool allConstant= true;
1518        for (iter= differentSecondVarLCs[i]; iter.hasItem(); iter++)
1519        {
1520          if (!iter.getItem().inCoeffDomain())
1521          {
1522            allConstant= false;
1523            y= Variable (iter.getItem().level());
1524          }
1525        }
1526        if (allConstant)
1527          continue;
1528
1529        bufFactors= differentSecondVarLCs [i];
1530        for (iter= bufFactors; iter.hasItem(); iter++)
1531          iter.getItem()= swapvar (iter.getItem(), x, y);
1532        bufF= F;
1533        z= Variable (y.level() - lev);
1534        bufF= swapvar (bufF, x, z);
1535        bufBufFactors= bufFactors;
1536        evalPoint= CFArray (evaluation.length() - 1);
1537        buf= CFArray (evaluation.length());
1538        iter= evaluation;
1539        int k= evaluation.length() - 1;
1540        for (; iter.hasItem(); iter++, k--)
1541          buf[k]= iter.getItem();
1542        swap= buf[z.level() - 1];
1543        buf[z.level() - 1]= buf[0];
1544        buf[0]= 0;
1545        int l= 0;
1546        for (k= 0; k < evaluation.length(); k++)
1547        {
1548          if (buf[k].isZero())
1549            continue;
1550          evalPoint[l]= buf[k];
1551          l++;
1552        }
1553        pass= testFactors (bufF, bufBufFactors, alpha, sqrfPartF, bufFactors,
1554                           bufSqrfFactors, evalSqrfPartF, evalPoint);
1555        if (pass)
1556        {
1557          foundDifferent= true;
1558          F= bufF;
1559          CFList l= factors;
1560          for (iter= l; iter.hasItem(); iter++)
1561            iter.getItem()= swapvar (iter.getItem(), x, y);
1562          differentSecondVarLCs [i]= l;
1563          j= i;
1564          break;
1565        }
1566        if (!pass && i == lSecondVarLCs - 1)
1567        {
1568          CFList result;
1569          result.append (LCF);
1570          for (int k= 1; k <= factors.length(); k++)
1571            result.append (LCF);
1572          y= Variable (1);
1573          delete [] bufSqrfFactors;
1574          return result;
1575        }
1576      }
1577    }
1578  }
1579  if (!pass)
1580  {
1581    CFList result;
1582    result.append (LCF);
1583    for (int k= 1; k <= factors.length(); k++)
1584      result.append (LCF);
1585    y= Variable (1);
1586    delete [] bufSqrfFactors;
1587    return result;
1588  }
1589  else
1590    factors= bufFactors;
1591
1592  bufFactors= factors;
1593  CFList evaluation2;
1594  if (y == x)
1595    evaluation2= evaluation;
1596  else
1597  {
1598    CanonicalForm tmp;
1599    evaluation2= evaluation;
1600    int i= evaluation.length() + 1;
1601    for (CFListIterator iter= evaluation2; iter.hasItem(); iter++, i--)
1602    {
1603      if (i == y.level())
1604      {
1605        tmp= iter.getItem();
1606        iter.getItem()= evaluation2.getLast();
1607        evaluation2.removeLast();
1608        evaluation2.append (tmp);
1609        break;
1610      }
1611    }
1612  }
1613
1614  CFList interMedResult;
1615  CanonicalForm oldSqrfPartF= sqrfPartF;
1616  sqrfPartF= shift2Zero (sqrfPartF, evalSqrfPartF, evaluation2, 1);
1617  if (factors.length() > 1)
1618  {
1619    CanonicalForm LC1= LC (oldSqrfPartF, 1);
1620    CFList leadingCoeffs;
1621    for (int i= 0; i < factors.length(); i++)
1622      leadingCoeffs.append (LC1);
1623
1624    CFList LC1eval= evaluateAtEval (LC1, evaluation2, 1);
1625    CFList oldFactors= factors;
1626    for (CFListIterator i= oldFactors; i.hasItem(); i++)
1627      i.getItem() *= LC1eval.getFirst()/Lc (i.getItem());
1628
1629    bool success= false;
1630    CanonicalForm oldSqrfPartFPowLC= oldSqrfPartF*power(LC1,factors.length()-1);
1631    if (size (oldSqrfPartFPowLC)/getNumVars (oldSqrfPartFPowLC) < 500 &&
1632        LucksWangSparseHeuristic (oldSqrfPartFPowLC,
1633                                  oldFactors, 1, leadingCoeffs, factors))
1634    {
1635      interMedResult= recoverFactors (oldSqrfPartF, factors);
1636      if (oldFactors.length() == interMedResult.length())
1637        success= true;
1638    }
1639    if (!success)
1640    {
1641      LC1= LC (evalSqrfPartF.getFirst(), 1);
1642
1643      CFArray leadingCoeffs= CFArray (factors.length());
1644      for (int i= 0; i < factors.length(); i++)
1645        leadingCoeffs[i]= LC1;
1646
1647      for (CFListIterator i= factors; i.hasItem(); i++)
1648      {
1649        i.getItem()= i.getItem() (x + evaluation2.getLast(), x);
1650        i.getItem() *= LC1 (0,2)/Lc (i.getItem());
1651      }
1652      factors.insert (1);
1653
1654      CanonicalForm
1655      newSqrfPartF= evalSqrfPartF.getFirst()*power (LC1, factors.length() - 2);
1656
1657      int liftBound= degree (newSqrfPartF,2) + 1;
1658
1659      CFMatrix M= CFMatrix (liftBound, factors.length() - 1);
1660      CFArray Pi;
1661      CFList diophant;
1662      nonMonicHenselLift12 (newSqrfPartF, factors, liftBound, Pi, diophant, M,
1663                            leadingCoeffs, false);
1664
1665      if (sqrfPartF.level() > 2)
1666      {
1667        int* liftBounds= new int [sqrfPartF.level() - 1];
1668        liftBounds [0]= liftBound;
1669        bool noOneToOne= false;
1670        CFList *leadingCoeffs2= new CFList [sqrfPartF.level()-2];
1671        LC1= LC (evalSqrfPartF.getLast(), 1);
1672        CFList LCs;
1673        for (int i= 0; i < factors.length(); i++)
1674          LCs.append (LC1);
1675        leadingCoeffs2 [sqrfPartF.level() - 3]= LCs;
1676        for (int i= sqrfPartF.level() - 1; i > 2; i--)
1677        {
1678          for (CFListIterator j= LCs; j.hasItem(); j++)
1679            j.getItem()= j.getItem() (0, i + 1);
1680          leadingCoeffs2 [i - 3]= LCs;
1681        }
1682        sqrfPartF *= power (LC1, factors.length()-1);
1683
1684        int liftBoundsLength= sqrfPartF.level() - 1;
1685        for (int i= 1; i < liftBoundsLength; i++)
1686          liftBounds [i]= degree (sqrfPartF, i + 2) + 1;
1687        evalSqrfPartF= evaluateAtZero (sqrfPartF);
1688        evalSqrfPartF.removeFirst();
1689        factors= nonMonicHenselLift (evalSqrfPartF, factors, leadingCoeffs2,
1690                 diophant, Pi, liftBounds, sqrfPartF.level() - 1, noOneToOne);
1691        delete [] leadingCoeffs2;
1692        delete [] liftBounds;
1693      }
1694      for (CFListIterator iter= factors; iter.hasItem(); iter++)
1695        iter.getItem()= reverseShift (iter.getItem(), evaluation2, 1);
1696
1697      interMedResult=
1698      recoverFactors (reverseShift(evalSqrfPartF.getLast(),evaluation2,1),
1699                      factors);
1700    }
1701  }
1702  else
1703  {
1704    factors= CFList (oldSqrfPartF);
1705    interMedResult= recoverFactors (oldSqrfPartF, factors);
1706  }
1707
1708  CFList result;
1709  CFFListIterator k;
1710  for (int i= 0; i < LCFFactors.length(); i++)
1711  {
1712    CanonicalForm tmp= 1;
1713    for (k= bufSqrfFactors[i]; k.hasItem(); k++)
1714    {
1715      int pos= findItem (bufFactors, k.getItem().factor());
1716      if (pos)
1717        tmp *= power (getItem (interMedResult, pos), k.getItem().exp());
1718    }
1719    result.append (tmp);
1720  }
1721
1722  for (CFListIterator i= result; i.hasItem(); i++)
1723  {
1724    F /= i.getItem();
1725    if (foundDifferent)
1726      i.getItem()= swapvar (i.getItem(), x, z);
1727    i.getItem()= N (i.getItem());
1728  }
1729
1730  if (foundDifferent)
1731  {
1732    CFList l= differentSecondVarLCs [j];
1733    for (CFListIterator i= l; i.hasItem(); i++)
1734      i.getItem()= swapvar (i.getItem(), y, z);
1735    differentSecondVarLCs [j]= l;
1736    F= swapvar (F, x, z);
1737  }
1738
1739  result.insert (N (F));
1740
1741  result= distributeContent (result, differentSecondVarLCs, lSecondVarLCs);
1742
1743  if (!result.getFirst().inCoeffDomain())
1744  {
1745    CFListIterator i= result;
1746    CanonicalForm tmp;
1747    if (foundDifferent)
1748      i.getItem()= swapvar (i.getItem(), Variable (2), y);
1749
1750    tmp= i.getItem();
1751
1752    i++;
1753    for (; i.hasItem(); i++)
1754    {
1755      if (foundDifferent)
1756        i.getItem()= swapvar (i.getItem(), Variable (2), y)*tmp;
1757      else
1758        i.getItem() *= tmp;
1759    }
1760  }
1761  else
1762    y= Variable (1);
1763
1764  delete [] bufSqrfFactors;
1765
1766  return result;
1767}
1768
1769void
1770evaluationWRTDifferentSecondVars (CFList*& Aeval, const CFList& evaluation,
1771                                  const CanonicalForm& A)
1772{
1773  CanonicalForm tmp;
1774  CFList tmp2;
1775  CFListIterator iter;
1776  for (int i= A.level(); i > 2; i--)
1777  {
1778    tmp= A;
1779    tmp2= CFList();
1780    iter= evaluation;
1781    bool preserveDegree= true;
1782    for (int j= A.level(); j > 1; j--, iter++)
1783    {
1784      if (j == i)
1785        continue;
1786      else
1787      {
1788        tmp= tmp (iter.getItem(), j);
1789        tmp2.insert (tmp);
1790        if ((degree (tmp, i) != degree (A, i)) ||
1791            (degree (tmp, 1) != degree (A, 1)))
1792        {
1793          preserveDegree= false;
1794          break;
1795        }
1796        if (!content(tmp).inCoeffDomain() || !content(tmp,1).inCoeffDomain())
1797        {
1798          preserveDegree= false;
1799          break;
1800        }
1801      }
1802    }
1803    if (preserveDegree)
1804      Aeval [i - 3]= tmp2;
1805    else
1806      Aeval [i - 3]= CFList();
1807  }
1808}
1809
1810#endif
1811
1812static inline
1813CanonicalForm prodEval (const CFList& l, const CanonicalForm& evalPoint,
1814                        const Variable& v)
1815{
1816  CanonicalForm result= 1;
1817  for (CFListIterator i= l; i.hasItem(); i++)
1818    result *= i.getItem() (evalPoint, v);
1819  return result;
1820}
1821
1822//recombine bivariate factors in case one bivariate factorization yields less
1823// factors than the other
1824CFList
1825recombination (const CFList& factors1, const CFList& factors2, int s, int thres,
1826               const CanonicalForm& evalPoint, const Variable& x)
1827{
1828  CFList T, S;
1829
1830  T= factors1;
1831  CFList result;
1832  CanonicalForm buf;
1833  int * v= new int [T.length()];
1834  for (int i= 0; i < T.length(); i++)
1835    v[i]= 0;
1836  bool nosubset= false;
1837  CFArray TT;
1838  TT= copy (factors1);
1839  while (T.length() >= 2*s && s <= thres)
1840  {
1841    while (nosubset == false) 
1842    {
1843      if (T.length() == s) 
1844      {
1845        delete [] v;
1846        result.append (prod (T));
1847        return result;
1848      }
1849      S= subset (v, s, TT, nosubset);
1850      if (nosubset) break;
1851      buf= prodEval (S, evalPoint, x);
1852      buf /= Lc (buf);
1853      if (find (factors2, buf))
1854      {
1855        T= Difference (T, S);
1856        result.append (prod (S));
1857        TT= copy (T);
1858        indexUpdate (v, s, T.length(), nosubset);
1859        if (nosubset) break;
1860      }
1861    }
1862    s++;
1863    if (T.length() < 2*s || T.length() == s) 
1864    {
1865      delete [] v;
1866      result.append (prod (T));
1867      return result;
1868    }
1869    for (int i= 0; i < T.length(); i++)
1870      v[i]= 0;
1871    nosubset= false;
1872  }
1873
1874  delete [] v;
1875  if (T.length() < 2*s)
1876  {
1877    result.append (prod (T));
1878    return result;
1879  }
1880
1881  return result;
1882}
1883
1884#ifdef HAVE_NTL
1885void
1886factorizationWRTDifferentSecondVars (const CanonicalForm& A, CFList*& Aeval,
1887                                     const ExtensionInfo& info,
1888                                     int& minFactorsLength, bool& irred)
1889{
1890  Variable x= Variable (1);
1891  minFactorsLength= 0;
1892  irred= false;
1893  CFList factors;
1894  Variable v;
1895  for (int j= 0; j < A.level() - 2; j++)
1896  {
1897    if (!Aeval[j].isEmpty())
1898    {
1899      v= Variable (Aeval[j].getFirst().level());
1900      if (CFFactory::gettype() == GaloisFieldDomain)
1901        factors= GFBiSqrfFactorize (Aeval[j].getFirst());
1902      else if (info.getAlpha().level() == 1)
1903        factors= FpBiSqrfFactorize (Aeval[j].getFirst());
1904      else
1905        factors= FqBiSqrfFactorize (Aeval[j].getFirst(), info.getAlpha());
1906
1907      factors.removeFirst();
1908      if (minFactorsLength == 0)
1909        minFactorsLength= factors.length();
1910      else
1911        minFactorsLength= tmin (minFactorsLength, factors.length());
1912
1913      if (factors.length() == 1)
1914      {
1915        irred= true;
1916        return;
1917      }
1918      sortList (factors, x);
1919      Aeval [j]= factors;
1920    }
1921  }
1922}
1923
1924void getLeadingCoeffs (const CanonicalForm& A, CFList*& Aeval,
1925                       const CFList& uniFactors, const CFList& evaluation
1926                      )
1927{
1928  CanonicalForm evalPoint;
1929  int i;
1930  CFListIterator iter, iter2;
1931  Variable v;
1932  CFList l, LCs, buf;
1933  int pos;
1934  for (int j= 0; j < A.level() - 2; j++)
1935  {
1936    if (!Aeval[j].isEmpty())
1937    {
1938      i= A.level();
1939      for (iter= evaluation; iter.hasItem(); iter++, i--)
1940      {
1941        if (i == Aeval[j].getFirst().level())
1942        {
1943          evalPoint= iter.getItem();
1944          break;
1945        }
1946      }
1947
1948      v= Variable (i);
1949      if (Aeval[j].length() > uniFactors.length())
1950        Aeval[j]= recombination (Aeval[j], uniFactors, 1,
1951                                 Aeval[j].length() - uniFactors.length() + 1,
1952                                 evalPoint, v);
1953
1954      l= CFList();
1955      buf= buildUniFactors (Aeval[j], evalPoint, v);
1956      for (iter= uniFactors; iter.hasItem(); iter++)
1957      {
1958        pos= findItem (buf, iter.getItem());
1959        if (pos)
1960          l.append (getItem (Aeval[j], pos));
1961      }
1962      Aeval [j]= l;
1963
1964      LCs= CFList();
1965      for (iter= Aeval[j]; iter.hasItem(); iter++)
1966        LCs.append (LC (iter.getItem(), 1));
1967      normalize (LCs);
1968      Aeval[j]= LCs;
1969    }
1970  }
1971}
1972
1973CFList
1974buildUniFactors (const CFList& biFactors, const CanonicalForm& evalPoint,
1975                 const Variable& y)
1976{
1977  CFList result;
1978  CanonicalForm tmp;
1979  for (CFListIterator i= biFactors; i.hasItem(); i++)
1980  {
1981    tmp= mod (i.getItem(), y - evalPoint);
1982    tmp /= Lc (tmp);
1983    result.append (tmp);
1984  }
1985  return result;
1986}
1987
1988void refineBiFactors (const CanonicalForm& A, CFList& biFactors,
1989                      CFList* const& Aeval, const CFList& evaluation,
1990                      int minFactorsLength)
1991{
1992  CFListIterator iter;
1993  CanonicalForm evalPoint;
1994  int i;
1995  Variable v;
1996  Variable y= Variable (2);
1997  CFList list;
1998  for (int j= 0; j < A.level() - 2; j++)
1999  {
2000    if (Aeval[j].length() == minFactorsLength)
2001    {
2002      i= A.level();
2003
2004      for (iter= evaluation; iter.hasItem(); iter++, i--)
2005      {
2006        if (i == Aeval[j].getFirst().level())
2007        {
2008          evalPoint= iter.getItem();
2009          break;
2010        }
2011      }
2012
2013      v= Variable (i);
2014      list= buildUniFactors (Aeval[j], evalPoint, v);
2015
2016      biFactors= recombination (biFactors, list, 1,
2017                                biFactors.length() - list.length() + 1,
2018                                evaluation.getLast(), y);
2019      return;
2020    }
2021  }
2022}
2023
2024void prepareLeadingCoeffs (CFList*& LCs, int n, const CFList& leadingCoeffs,
2025                           const CFList& biFactors, const CFList& evaluation)
2026{
2027  CFList l= leadingCoeffs;
2028  LCs [n-3]= l;
2029  CFListIterator j;
2030  CFListIterator iter= evaluation;
2031  for (int i= n - 1; i > 2; i--, iter++)
2032  {
2033    for (j= l; j.hasItem(); j++)
2034      j.getItem()= j.getItem() (iter.getItem(), i + 1);
2035    LCs [i - 3]= l;
2036  }
2037  l= LCs [0];
2038  for (CFListIterator i= l; i.hasItem(); i++)
2039    i.getItem()= i.getItem() (iter.getItem(), 3);
2040  CFListIterator ii= biFactors;
2041  CFList normalizeFactor;
2042  for (CFListIterator i= l; i.hasItem(); i++, ii++)
2043    normalizeFactor.append (Lc (LC (ii.getItem(), 1))/Lc (i.getItem()));
2044  for (int i= 0; i < n-2; i++)
2045  {
2046    ii= normalizeFactor;
2047    for (j= LCs [i]; j.hasItem(); j++, ii++)
2048      j.getItem() *= ii.getItem();
2049  }
2050}
2051
2052CFList recoverFactors (const CanonicalForm& F, const CFList& factors)
2053{
2054  CFList result;
2055  CanonicalForm tmp, tmp2;
2056  CanonicalForm G= F;
2057  for (CFListIterator i= factors; i.hasItem(); i++)
2058  {
2059    tmp= i.getItem()/content (i.getItem(), 1);
2060    if (fdivides (tmp, G, tmp2))
2061    {
2062      G= tmp2;
2063      result.append (tmp);
2064    }
2065  }
2066  return result;
2067}
2068
2069CFList recoverFactors (const CanonicalForm& F, const CFList& factors,
2070                       const CFList& evaluation)
2071{
2072  CFList result;
2073  CanonicalForm tmp, tmp2;
2074  CanonicalForm G= F;
2075  for (CFListIterator i= factors; i.hasItem(); i++)
2076  {
2077    tmp= reverseShift (i.getItem(), evaluation);
2078    tmp /= content (tmp, 1);
2079    if (fdivides (tmp, G, tmp2))
2080    {
2081      G= tmp2;
2082      result.append (tmp);
2083    }
2084  }
2085  return result;
2086}
2087
2088CFList
2089extNonMonicFactorRecombination (const CFList& factors, const CanonicalForm& F,
2090                                const ExtensionInfo& info)
2091{
2092  Variable alpha= info.getAlpha();
2093  Variable beta= info.getBeta();
2094  CanonicalForm gamma= info.getGamma();
2095  CanonicalForm delta= info.getDelta();
2096  int k= info.getGFDegree();
2097  CFList source, dest;
2098
2099  int degMipoBeta= 1;
2100  if (!k && beta != Variable(1))
2101    degMipoBeta= degree (getMipo (beta));
2102
2103  CFList T, S;
2104  T= factors;
2105  int s= 1;
2106  CFList result;
2107  CanonicalForm quot, buf= F;
2108
2109  CanonicalForm g;
2110  CanonicalForm buf2;
2111  int * v= new int [T.length()];
2112  for (int i= 0; i < T.length(); i++)
2113    v[i]= 0;
2114  bool noSubset= false;
2115  CFArray TT;
2116  TT= copy (factors);
2117  bool recombination= false;
2118  bool trueFactor= false;
2119  while (T.length() >= 2*s)
2120  {
2121    while (noSubset == false)
2122    {
2123      if (T.length() == s)
2124      {
2125        delete [] v;
2126        if (recombination)
2127        {
2128          g= prod (T);
2129          T.removeFirst();
2130          result.append (g/myContent (g));
2131          g /= Lc (g);
2132          appendTestMapDown (result, g, info, source, dest);
2133          return result;
2134        }
2135        else
2136          return CFList (buf/myContent(buf));
2137      }
2138
2139      S= subset (v, s, TT, noSubset);
2140      if (noSubset) break;
2141
2142      g= prod (S);
2143      g /= myContent (g);
2144      if (fdivides (g, buf, quot))
2145      {
2146        buf2= g;
2147        buf2 /= Lc (buf2);
2148        if (!k && beta.level() == 1)
2149        {
2150          if (degree (buf2, alpha) < degMipoBeta)
2151          {
2152            appendTestMapDown (result, buf2, info, source, dest);
2153            buf= quot;
2154            recombination= true;
2155            trueFactor= true;
2156          }
2157        }
2158        else
2159        {
2160          if (!isInExtension (buf2, gamma, k, delta, source, dest))
2161          {
2162            appendTestMapDown (result, buf2, info, source, dest);
2163            buf= quot;
2164            recombination= true;
2165            trueFactor= true;
2166          }
2167        }
2168        if (trueFactor)
2169        {
2170          T= Difference (T, S);
2171
2172          if (T.length() < 2*s || T.length() == s)
2173          {
2174            delete [] v;
2175            buf /= myContent (buf);
2176            buf /= Lc (buf);
2177            appendTestMapDown (result, buf, info, source, dest);
2178            return result;
2179          }
2180          trueFactor= false;
2181          TT= copy (T);
2182          indexUpdate (v, s, T.length(), noSubset);
2183          if (noSubset) break;
2184        }
2185      }
2186    }
2187    s++;
2188    if (T.length() < 2*s || T.length() == s)
2189    {
2190      delete [] v;
2191      appendTestMapDown (result, buf/myContent(buf), info, source, dest);
2192      return result;
2193    }
2194    for (int i= 0; i < T.length(); i++)
2195      v[i]= 0;
2196    noSubset= false;
2197  }
2198  if (T.length() < 2*s)
2199    appendMapDown (result, F/myContent(F), info, source, dest);
2200
2201  delete [] v;
2202  return result;
2203}
2204
2205CFList
2206extFactorize (const CanonicalForm& F, const ExtensionInfo& info);
2207
2208CFList
2209multiFactorize (const CanonicalForm& F, const ExtensionInfo& info)
2210{
2211
2212  if (F.inCoeffDomain())
2213    return CFList (F);
2214
2215  // compress and find main Variable
2216  CFMap N;
2217  CanonicalForm A= myCompress (F, N);
2218
2219  A /= Lc (A); // make monic
2220
2221  Variable alpha= info.getAlpha();
2222  Variable beta= info.getBeta();
2223  CanonicalForm gamma= info.getGamma();
2224  CanonicalForm delta= info.getDelta();
2225  bool extension= info.isInExtension();
2226  bool GF= (CFFactory::gettype() == GaloisFieldDomain);
2227  //univariate case
2228  if (F.isUnivariate())
2229  {
2230    if (extension == false)
2231      return uniFactorizer (F, alpha, GF);
2232    else
2233    {
2234      CFList source, dest;
2235      A= mapDown (F, info, source, dest);
2236      return uniFactorizer (A, beta, GF);
2237    }
2238  }
2239
2240  //bivariate case
2241  if (A.level() == 2)
2242  {
2243    CFList buf= biFactorize (F, info);
2244    return buf;
2245  }
2246
2247  Variable x= Variable (1);
2248  Variable y= Variable (2);
2249
2250  // remove content
2251  CFList contentAi;
2252  CanonicalForm lcmCont= lcmContent (A, contentAi);
2253  A /= lcmCont;
2254
2255  // trivial after content removal
2256  CFList contentAFactors;
2257  if (A.inCoeffDomain())
2258  {
2259    for (CFListIterator i= contentAi; i.hasItem(); i++)
2260    {
2261      if (i.getItem().inCoeffDomain())
2262        continue;
2263      else
2264      {
2265        lcmCont /= i.getItem();
2266        contentAFactors=
2267        Union (multiFactorize (lcmCont, info),
2268               multiFactorize (i.getItem(), info));
2269        break;
2270      }
2271    }
2272    decompress (contentAFactors, N);
2273    normalize (contentAFactors);
2274    return contentAFactors;
2275  }
2276
2277  // factorize content
2278  contentAFactors= multiFactorize (lcmCont, info);
2279
2280  // univariate after content removal
2281  CFList factors;
2282  if (A.isUnivariate ())
2283  {
2284    factors= uniFactorizer (A, alpha, GF);
2285    append (factors, contentAFactors);
2286    decompress (factors, N);
2287    return factors;
2288  }
2289
2290  // check main variable
2291  int swapLevel= 0;
2292  CanonicalForm derivZ;
2293  CanonicalForm gcdDerivZ;
2294  CanonicalForm bufA= A;
2295  Variable z;
2296  for (int i= 1; i <= A.level(); i++)
2297  {
2298    z= Variable (i);
2299    derivZ= deriv (bufA, z);
2300    if (derivZ.isZero())
2301    {
2302      if (i == 1)
2303        swapLevel= 1;
2304      else
2305        continue;
2306    }
2307    else
2308    {
2309      if (swapLevel == 1)
2310      {
2311        swapLevel= i;
2312        bufA= swapvar (A, x, z);
2313      }
2314      gcdDerivZ= gcd (bufA, derivZ);
2315      if (degree (gcdDerivZ) > 0 && !derivZ.isZero())
2316      {
2317        CanonicalForm g= bufA/gcdDerivZ;
2318        CFList factorsG=
2319        Union (multiFactorize (g, info),
2320               multiFactorize (gcdDerivZ, info));
2321        appendSwapDecompress (factorsG, contentAFactors, N, swapLevel, x);
2322        normalize (factorsG);
2323        return factorsG;
2324      }
2325      else
2326      {
2327        A= bufA;
2328        break;
2329      }
2330    }
2331  }
2332
2333
2334  CFList Aeval, list, evaluation, bufEvaluation, bufAeval;
2335  bool fail= false;
2336  int swapLevel2= 0;
2337  int level;
2338  int factorNums= 3;
2339  CanonicalForm bivarEval;
2340  CFList biFactors, bufBiFactors;
2341  CanonicalForm evalPoly;
2342  int lift, bufLift;
2343  double logarithm= (double) ilog2 (totaldegree (A));
2344  logarithm /= log2exp;
2345  logarithm= ceil (logarithm);
2346  if (factorNums < (int) logarithm)
2347    factorNums= (int) logarithm;
2348  CFList* bufAeval2= new CFList [A.level() - 2];
2349  CFList* Aeval2= new CFList [A.level() - 2];
2350  int counter;
2351  int differentSecondVar= 0;
2352  // several bivariate factorizations
2353  for (int i= 0; i < factorNums; i++)
2354  {
2355    counter= 0;
2356    bufA= A;
2357    bufAeval= CFList();
2358    bufEvaluation= evalPoints (bufA, bufAeval, alpha, list, GF, fail);
2359    evalPoly= 0;
2360
2361    if (fail && (i == 0))
2362    {
2363      if (!swapLevel)
2364        level= 2;
2365      else
2366        level= swapLevel + 1;
2367
2368      CanonicalForm g;
2369      swapLevel2= newMainVariableSearch (A, Aeval, evaluation, alpha, level, g);
2370
2371      if (!swapLevel2) // need to pass to an extension
2372      {
2373        factors= extFactorize (A, info);
2374        appendSwapDecompress (factors, contentAFactors, N, swapLevel, x);
2375        normalize (factors);
2376        delete [] bufAeval2;
2377        delete [] Aeval2;
2378        return factors;
2379      }
2380      else
2381      {
2382        if (swapLevel2 == -1)
2383        {
2384          CFList factorsG=
2385          Union (multiFactorize (g, info),
2386                 multiFactorize (A/g, info));
2387          appendSwapDecompress (factorsG, contentAFactors, N, swapLevel, x);
2388          normalize (factorsG);
2389          delete [] bufAeval2;
2390          delete [] Aeval2;
2391          return factorsG;
2392        }
2393        fail= false;
2394        bufAeval= Aeval;
2395        bufA= A;
2396        bufEvaluation= evaluation;
2397      }
2398    }
2399    else if (fail && (i > 0))
2400      break;
2401
2402    bivarEval= bufEvaluation.getLast();
2403
2404    evaluationWRTDifferentSecondVars (bufAeval2, bufEvaluation, A);
2405
2406    for (int j= 0; j < A.level() - 2; j++)
2407    {
2408      if (!bufAeval2[j].isEmpty())
2409        counter++;
2410    }
2411
2412    bufLift= degree (A, y) + 1 + degree (LC(A, x), y);
2413
2414    TIMING_START (fac_bi_factorizer);
2415    if (!GF && alpha.level() == 1)
2416      bufBiFactors= FpBiSqrfFactorize (bufAeval.getFirst());
2417    else if (GF)
2418      bufBiFactors= GFBiSqrfFactorize (bufAeval.getFirst());
2419    else
2420      bufBiFactors= FqBiSqrfFactorize (bufAeval.getFirst(), alpha);
2421    TIMING_END_AND_PRINT (fac_bi_factorizer,
2422                          "time for bivariate factorization: ");
2423    bufBiFactors.removeFirst();
2424
2425    if (bufBiFactors.length() == 1)
2426    {
2427      if (extension)
2428      {
2429        CFList source, dest;
2430        A= mapDown (A, info, source, dest);
2431      }
2432      factors.append (A);
2433      appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2434                            swapLevel2, x);
2435      normalize (factors);
2436      delete [] bufAeval2;
2437      delete [] Aeval2;
2438      return factors;
2439    }
2440
2441    if (i == 0)
2442    {
2443      Aeval= bufAeval;
2444      evaluation= bufEvaluation;
2445      biFactors= bufBiFactors;
2446      lift= bufLift;
2447      for (int j= 0; j < A.level() - 2; j++)
2448        Aeval2 [j]= bufAeval2 [j];
2449      differentSecondVar= counter;
2450    }
2451    else
2452    {
2453      if (bufBiFactors.length() < biFactors.length() ||
2454          ((bufLift < lift) && (bufBiFactors.length() == biFactors.length())) ||
2455          counter > differentSecondVar)
2456      {
2457        Aeval= bufAeval;
2458        evaluation= bufEvaluation;
2459        biFactors= bufBiFactors;
2460        lift= bufLift;
2461        for (int j= 0; j < A.level() - 2; j++)
2462          Aeval2 [j]= bufAeval2 [j];
2463        differentSecondVar= counter;
2464      }
2465    }
2466    int k= 0;
2467    for (CFListIterator j= bufEvaluation; j.hasItem(); j++, k++)
2468      evalPoly += j.getItem()*power (x, k);
2469    list.append (evalPoly);
2470  }
2471
2472  delete [] bufAeval2;
2473
2474  sortList (biFactors, x);
2475
2476  int minFactorsLength;
2477  bool irred= false;
2478  factorizationWRTDifferentSecondVars (A, Aeval2, info, minFactorsLength, irred);
2479
2480  if (irred)
2481  {
2482    if (extension)
2483    {
2484      CFList source, dest;
2485      A= mapDown (A, info, source, dest);
2486    }
2487    factors.append (A);
2488    appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2489                          swapLevel2, x);
2490    normalize (factors);
2491    delete [] Aeval2;
2492    return factors;
2493  }
2494
2495  if (minFactorsLength == 0)
2496    minFactorsLength= biFactors.length();
2497  else if (biFactors.length() > minFactorsLength)
2498    refineBiFactors (A, biFactors, Aeval2, evaluation, minFactorsLength);
2499  minFactorsLength= tmin (minFactorsLength, biFactors.length());
2500
2501  if (differentSecondVar == A.level() - 2)
2502  {
2503    bool zeroOccured= false;
2504    for (CFListIterator iter= evaluation; iter.hasItem(); iter++)
2505    {
2506      if (iter.getItem().isZero())
2507      {
2508        zeroOccured= true;
2509        break;
2510      }
2511    }
2512    if (!zeroOccured)
2513    {
2514      factors= sparseHeuristic (A, biFactors, Aeval2, evaluation, minFactorsLength);
2515      if (factors.length() == biFactors.length())
2516      {
2517        if (extension)
2518          factors= extNonMonicFactorRecombination (factors, A, info);
2519
2520        appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2521                              swapLevel2, x);
2522        normalize (factors);
2523        delete [] Aeval2;
2524        return factors;
2525      }
2526      else
2527        factors= CFList();
2528      //TODO case where factors.length() > 0
2529    }
2530  }
2531
2532  CFList uniFactors= buildUniFactors (biFactors, evaluation.getLast(), y);
2533
2534  CFList * oldAeval= new CFList [A.level() - 2]; //TODO use bufAeval2 for this
2535  for (int i= 0; i < A.level() - 2; i++)
2536    oldAeval[i]= Aeval2[i];
2537
2538  getLeadingCoeffs (A, Aeval2, uniFactors, evaluation);
2539
2540  CFList biFactorsLCs;
2541  for (CFListIterator i= biFactors; i.hasItem(); i++)
2542    biFactorsLCs.append (LC (i.getItem(), 1));
2543
2544  Variable v;
2545  CFList leadingCoeffs= precomputeLeadingCoeff (LC (A, 1), biFactorsLCs, alpha,
2546                                          evaluation, Aeval2, A.level() - 2, v);
2547
2548  if (v.level() != 1)
2549  {
2550    A= swapvar (A, y, v);
2551    for (int i= 0; i < A.level() - 2; i++)
2552    {
2553      if (oldAeval[i].isEmpty())
2554        continue;
2555      if (oldAeval[i].getFirst().level() == v.level())
2556      {
2557        biFactors= CFList();
2558        for (CFListIterator iter= oldAeval [i]; iter.hasItem(); iter++)
2559          biFactors.append (swapvar (iter.getItem(), v, y));
2560      }
2561    }
2562    int i= A.level();
2563    CanonicalForm evalPoint;
2564    for (CFListIterator iter= evaluation; iter.hasItem(); iter++, i--)
2565    {
2566      if (i == v.level())
2567      {
2568        evalPoint= iter.getItem();
2569        iter.getItem()= evaluation.getLast();
2570        evaluation.removeLast();
2571        evaluation.append (evalPoint);
2572        break;
2573      }
2574    }
2575  }
2576
2577  CFListIterator iter;
2578  CanonicalForm oldA= A;
2579  CFList oldBiFactors= biFactors;
2580  if (!leadingCoeffs.getFirst().inCoeffDomain())
2581  {
2582    CanonicalForm tmp= power (leadingCoeffs.getFirst(), biFactors.length() - 1);
2583    A *= tmp;
2584    tmp= leadingCoeffs.getFirst();
2585    iter= evaluation;
2586    for (int i= A.level(); i > 2; i--, iter++)
2587      tmp= tmp (iter.getItem(), i);
2588    if (!tmp.inCoeffDomain())
2589    {
2590      for (CFListIterator i= biFactors; i.hasItem(); i++)
2591      {
2592        i.getItem() *= tmp/LC (i.getItem(), 1);
2593        i.getItem() /= Lc (i.getItem());
2594      }
2595    }
2596  }
2597
2598  leadingCoeffs.removeFirst();
2599
2600  //prepare leading coefficients
2601  CFList* leadingCoeffs2= new CFList [A.level() - 2];
2602  prepareLeadingCoeffs (leadingCoeffs2, A.level(), leadingCoeffs, biFactors,
2603                        evaluation);
2604
2605  Aeval= evaluateAtEval (A, evaluation, 2);
2606  CanonicalForm hh= Lc (Aeval.getFirst());
2607  for (iter= Aeval; iter.hasItem(); iter++)
2608    iter.getItem() /= hh;
2609
2610  A /= hh;
2611
2612  if (size (A)/getNumVars (A) < 500 && 
2613      LucksWangSparseHeuristic (A, biFactors, 2, leadingCoeffs2 [A.level() - 3],
2614                                factors))
2615  {
2616    int check= factors.length();
2617    factors= recoverFactors (A, factors);
2618
2619    if (check == factors.length())
2620    {
2621      if (extension)
2622        factors= extNonMonicFactorRecombination (factors, A, info);
2623
2624      if (v.level() != 1)
2625      {
2626        for (CFListIterator iter= factors; iter.hasItem(); iter++)
2627          iter.getItem()= swapvar (iter.getItem(), v, y);
2628      }
2629      appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2630                            swapLevel2, x);
2631      normalize (factors);
2632      delete [] Aeval2;
2633      return factors;
2634    }
2635    else
2636      factors= CFList();
2637    //TODO handle this case
2638  }
2639
2640  A= shift2Zero (A, Aeval, evaluation);
2641
2642  for (iter= biFactors; iter.hasItem(); iter++)
2643    iter.getItem()= iter.getItem () (y + evaluation.getLast(), y);
2644
2645  for (int i= 0; i < A.level() - 2; i++)
2646  {
2647    if (i != A.level() - 3)
2648      leadingCoeffs2[i]= CFList();
2649  }
2650  for (iter= leadingCoeffs2[A.level() - 3]; iter.hasItem(); iter++)
2651  {
2652    iter.getItem()= shift2Zero (iter.getItem(), list, evaluation);
2653    for (int i= A.level() - 4; i > -1; i--)
2654    {
2655      if (i + 1 == A.level() - 3)
2656        leadingCoeffs2[i].append (iter.getItem() (0, i + 4));
2657      else
2658        leadingCoeffs2[i].append (leadingCoeffs2[i+1].getLast() (0, i + 4));
2659    }
2660  }
2661
2662  CFArray Pi;
2663  CFList diophant;
2664  int* liftBounds= new int [A.level() - 1];
2665  int liftBoundsLength= A.level() - 1;
2666  for (int i= 0; i < liftBoundsLength; i++)
2667    liftBounds [i]= degree (A, i + 2) + 1;
2668
2669  Aeval.removeFirst();
2670  bool noOneToOne= false;
2671  factors= nonMonicHenselLift (Aeval, biFactors, leadingCoeffs2, diophant,
2672                               Pi, liftBounds, liftBoundsLength, noOneToOne);
2673
2674  if (!noOneToOne)
2675  {
2676    int check= factors.length();
2677    A= oldA;
2678    factors= recoverFactors (A, factors, evaluation);
2679    if (check != factors.length())
2680      noOneToOne= true;
2681
2682    if (extension && !noOneToOne)
2683      factors= extNonMonicFactorRecombination (factors, A, info);
2684  }
2685  if (noOneToOne)
2686  {
2687    A= shift2Zero (oldA, Aeval, evaluation);
2688    biFactors= oldBiFactors;
2689    for (iter= biFactors; iter.hasItem(); iter++)
2690      iter.getItem()= iter.getItem () (y + evaluation.getLast(), y);
2691    CanonicalForm LCA= LC (Aeval.getFirst(), 1);
2692    CanonicalForm yToLift= power (y, lift);
2693    CFListIterator i= biFactors;
2694    lift= degree (i.getItem(), 2) + degree (LC (i.getItem(), 1)) + 1;
2695    i++;
2696
2697    for (; i.hasItem(); i++)
2698      lift= tmax (lift, degree (i.getItem(), 2) + degree (LC (i.getItem(), 1)) + 1);
2699
2700    lift= tmax (degree (Aeval.getFirst() , 2) + 1, lift);
2701
2702    i= biFactors;
2703    yToLift= power (y, lift);
2704    CanonicalForm dummy;
2705    for (; i.hasItem(); i++)
2706    {
2707      LCA= LC (i.getItem(), 1);
2708      extgcd (LCA, yToLift, LCA, dummy);
2709      i.getItem()= mod (i.getItem()*LCA, yToLift);
2710    }
2711
2712    liftBoundsLength= F.level() - 1;
2713    liftBounds= liftingBounds (A, lift);
2714
2715    CFList MOD;
2716    bool earlySuccess;
2717    CFList earlyFactors, liftedFactors;
2718    TIMING_START (fac_hensel_lift);
2719    liftedFactors= henselLiftAndEarly
2720                   (A, MOD, liftBounds, earlySuccess, earlyFactors,
2721                    Aeval, biFactors, evaluation, info);
2722    TIMING_END_AND_PRINT (fac_hensel_lift, "time for hensel lifting: ");
2723
2724    if (!extension)
2725    {
2726      TIMING_START (fac_factor_recombination);
2727      factors= factorRecombination (A, liftedFactors, MOD);
2728      TIMING_END_AND_PRINT (fac_factor_recombination,
2729                            "time for factor recombination: ");
2730    }
2731    else
2732    {
2733      TIMING_START (fac_factor_recombination);
2734      factors= extFactorRecombination (liftedFactors, A, MOD, info, evaluation);
2735      TIMING_END_AND_PRINT (fac_factor_recombination,
2736                            "time for factor recombination: ");
2737    }
2738
2739    if (earlySuccess)
2740      factors= Union (factors, earlyFactors);
2741    if (!extension)
2742    {
2743      for (CFListIterator i= factors; i.hasItem(); i++)
2744      {
2745        int kk= Aeval.getLast().level();
2746        for (CFListIterator j= evaluation; j.hasItem(); j++, kk--)
2747        {
2748          if (i.getItem().level() < kk)
2749            continue;
2750          i.getItem()= i.getItem() (Variable (kk) - j.getItem(), kk);
2751        }
2752      }
2753    }
2754  }
2755
2756  if (v.level() != 1)
2757  {
2758    for (CFListIterator iter= factors; iter.hasItem(); iter++)
2759      iter.getItem()= swapvar (iter.getItem(), v, y);
2760  }
2761
2762  swap (factors, swapLevel, swapLevel2, x);
2763  append (factors, contentAFactors);
2764  decompress (factors, N);
2765  normalize (factors);
2766
2767  delete[] liftBounds;
2768
2769  return factors;
2770}
2771
2772/// multivariate factorization over an extension of the initial field
2773CFList
2774extFactorize (const CanonicalForm& F, const ExtensionInfo& info)
2775{
2776  CanonicalForm A= F;
2777
2778  Variable alpha= info.getAlpha();
2779  Variable beta= info.getBeta();
2780  int k= info.getGFDegree();
2781  char cGFName= info.getGFName();
2782  CanonicalForm delta= info.getDelta();
2783  bool GF= (CFFactory::gettype() == GaloisFieldDomain);
2784  Variable w= Variable (1);
2785
2786  CFList factors;
2787  if (!GF && alpha == w)  // we are in F_p
2788  {
2789    CFList factors;
2790    bool extension= true;
2791    int p= getCharacteristic();
2792    if (p*p < (1<<16)) // pass to GF if possible
2793    {
2794      setCharacteristic (getCharacteristic(), 2, 'Z');
2795      ExtensionInfo info= ExtensionInfo (extension);
2796      A= A.mapinto();
2797      factors= multiFactorize (A, info);
2798
2799      CanonicalForm mipo= gf_mipo;
2800      setCharacteristic (getCharacteristic());
2801      Variable vBuf= rootOf (mipo.mapinto());
2802      for (CFListIterator j= factors; j.hasItem(); j++)
2803        j.getItem()= GF2FalphaRep (j.getItem(), vBuf);
2804    }
2805    else  // not able to pass to GF, pass to F_p(\alpha)
2806    {
2807      CanonicalForm mipo= randomIrredpoly (2, w);
2808      Variable v= rootOf (mipo);
2809      ExtensionInfo info= ExtensionInfo (v);
2810      factors= multiFactorize (A, info);
2811    }
2812    return factors;
2813  }
2814  else if (!GF && (alpha != w)) // we are in F_p(\alpha)
2815  {
2816    if (k == 1) // need factorization over F_p
2817    {
2818      int extDeg= degree (getMipo (alpha));
2819      extDeg++;
2820      CanonicalForm mipo= randomIrredpoly (extDeg + 1, w);
2821      Variable v= rootOf (mipo);
2822      ExtensionInfo info= ExtensionInfo (v);
2823      factors= multiFactorize (A, info);
2824    }
2825    else
2826    {
2827      if (beta == w)
2828      {
2829        Variable v= chooseExtension (alpha, beta, k);
2830        CanonicalForm primElem, imPrimElem;
2831        bool primFail= false;
2832        Variable vBuf;
2833        primElem= primitiveElement (alpha, vBuf, primFail);
2834        ASSERT (!primFail, "failure in integer factorizer");
2835        if (primFail)
2836          ; //ERROR
2837        else
2838          imPrimElem= mapPrimElem (primElem, vBuf, v);
2839
2840        CFList source, dest;
2841        CanonicalForm bufA= mapUp (A, alpha, v, primElem, imPrimElem,
2842                                   source, dest);
2843        ExtensionInfo info= ExtensionInfo (v, alpha, imPrimElem, primElem);
2844        factors= multiFactorize (bufA, info);
2845      }
2846      else
2847      {
2848        Variable v= chooseExtension (alpha, beta, k);
2849        CanonicalForm primElem, imPrimElem;
2850        bool primFail= false;
2851        Variable vBuf;
2852        ASSERT (!primFail, "failure in integer factorizer");
2853        if (primFail)
2854          ; //ERROR
2855        else
2856          imPrimElem= mapPrimElem (delta, beta, v);
2857
2858        CFList source, dest;
2859        CanonicalForm bufA= mapDown (A, info, source, dest);
2860        source= CFList();
2861        dest= CFList();
2862        bufA= mapUp (bufA, beta, v, delta, imPrimElem, source, dest);
2863        ExtensionInfo info= ExtensionInfo (v, beta, imPrimElem, delta);
2864        factors= multiFactorize (bufA, info);
2865      }
2866    }
2867    return factors;
2868  }
2869  else // we are in GF (p^k)
2870  {
2871    int p= getCharacteristic();
2872    int extensionDeg= getGFDegree();
2873    bool extension= true;
2874    if (k == 1) // need factorization over F_p
2875    {
2876      extensionDeg++;
2877      if (pow ((double) p, (double) extensionDeg) < (1<<16))
2878      // pass to GF(p^k+1)
2879      {
2880        CanonicalForm mipo= gf_mipo;
2881        setCharacteristic (p);
2882        Variable vBuf= rootOf (mipo.mapinto());
2883        A= GF2FalphaRep (A, vBuf);
2884        setCharacteristic (p, extensionDeg, 'Z');
2885        ExtensionInfo info= ExtensionInfo (extension);
2886        factors= multiFactorize (A.mapinto(), info);
2887      }
2888      else // not able to pass to another GF, pass to F_p(\alpha)
2889      {
2890        CanonicalForm mipo= gf_mipo;
2891        setCharacteristic (p);
2892        Variable vBuf= rootOf (mipo.mapinto());
2893        A= GF2FalphaRep (A, vBuf);
2894        Variable v= chooseExtension (vBuf, beta, k);
2895        ExtensionInfo info= ExtensionInfo (v, extension);
2896        factors= multiFactorize (A, info);
2897      }
2898    }
2899    else // need factorization over GF (p^k)
2900    {
2901      if (pow ((double) p, (double) 2*extensionDeg) < (1<<16))
2902      // pass to GF(p^2k)
2903      {
2904        setCharacteristic (p, 2*extensionDeg, 'Z');
2905        ExtensionInfo info= ExtensionInfo (k, cGFName, extension);
2906        factors= multiFactorize (GFMapUp (A, extensionDeg), info);
2907        setCharacteristic (p, extensionDeg, cGFName);
2908      }
2909      else // not able to pass to GF (p^2k), pass to F_p (\alpha)
2910      {
2911        CanonicalForm mipo= gf_mipo;
2912        setCharacteristic (p);
2913        Variable v1= rootOf (mipo.mapinto());
2914        A= GF2FalphaRep (A, v1);
2915        Variable v2= chooseExtension (v1, v1, k);
2916        CanonicalForm primElem, imPrimElem;
2917        bool primFail= false;
2918        Variable vBuf;
2919        primElem= primitiveElement (v1, v1, primFail);
2920        if (primFail)
2921          ; //ERROR
2922        else
2923          imPrimElem= mapPrimElem (primElem, v1, v2);
2924        CFList source, dest;
2925        CanonicalForm bufA= mapUp (A, v1, v2, primElem, imPrimElem,
2926                                     source, dest);
2927        ExtensionInfo info= ExtensionInfo (v2, v1, imPrimElem, primElem);
2928        factors= multiFactorize (bufA, info);
2929        setCharacteristic (p, k, cGFName);
2930        for (CFListIterator i= factors; i.hasItem(); i++)
2931          i.getItem()= Falpha2GFRep (i.getItem());
2932      }
2933    }
2934    return factors;
2935  }
2936}
2937
2938#endif
2939/* HAVE_NTL */
2940
Note: See TracBrowser for help on using the repository browser.