source: git/factory/facFqFactorize.cc @ 346edc8

spielwiese
Last change on this file since 346edc8 was a54114, checked in by Martin Lee <martinlee84@…>, 12 years ago
chg: replaced Variable (1)
  • Property mode set to 100644
File size: 74.9 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
35#ifdef HAVE_NTL
36#include <NTL/ZZ_pEX.h>
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        iter2.getItem() /= tmp;
1263        content /= g;
1264        iter1.getItem() *= g;
1265      }
1266    }
1267  }
1268
1269  l.removeFirst();
1270  l.insert (content);
1271  return l;
1272}
1273
1274CFList evaluateAtZero (const CanonicalForm& F)
1275{
1276  CFList result;
1277  CanonicalForm buf= F;
1278  result.insert (buf);
1279  for (int i= F.level(); i > 2; i--)
1280  {
1281    buf= buf (0, i);
1282    result.insert (buf);
1283  }
1284  return result;
1285}
1286
1287CFList evaluateAtEval (const CanonicalForm& F, const CFArray& eval)
1288{
1289  CFList result;
1290  CanonicalForm buf= F;
1291  result.insert (buf);
1292  int k= eval.size();
1293  for (int i= 1; i < k; i++)
1294  {
1295    buf= buf (eval[i], i + 2);
1296    result.insert (buf);
1297  }
1298  return result;
1299}
1300
1301CFList evaluateAtEval (const CanonicalForm& F, const CFList& evaluation, int l)
1302{
1303  CFList result;
1304  CanonicalForm buf= F;
1305  result.insert (buf);
1306  int k= evaluation.length() + l - 1;
1307  CFListIterator j= evaluation;
1308  for (int i= k; j.hasItem() && i > l; i--, j++)
1309  {
1310    if (F.level() < i)
1311      continue;
1312    buf= buf (j.getItem(), i);
1313    result.insert (buf);
1314  }
1315  return result;
1316}
1317
1318int
1319testFactors (const CanonicalForm& G, const CFList& uniFactors,
1320             const Variable& alpha, CanonicalForm& sqrfPartF, CFList& factors,
1321             CFFList*& bufSqrfFactors, CFList& evalSqrfPartF,
1322             const CFArray& evalPoint)
1323{
1324  CanonicalForm tmp;
1325  CFListIterator j;
1326  for (CFListIterator i= uniFactors; i.hasItem(); i++)
1327  {
1328    tmp= i.getItem();
1329    if (i.hasItem())
1330      i++;
1331    else
1332      break;
1333    for (j= i; j.hasItem(); j++)
1334    {
1335      if (tmp == j.getItem())
1336        return 0;
1337    }
1338  }
1339
1340  CanonicalForm F= G;
1341  CFFList sqrfFactorization= squarefreeFactorization (F, alpha);
1342
1343  sqrfPartF= 1;
1344  for (CFFListIterator i= sqrfFactorization; i.hasItem(); i++)
1345    sqrfPartF *= i.getItem().factor();
1346
1347  evalSqrfPartF= evaluateAtEval (sqrfPartF, evalPoint);
1348
1349  CanonicalForm test= evalSqrfPartF.getFirst() (evalPoint[0], 2);
1350
1351  if (degree (test) != degree (sqrfPartF, 1))
1352    return 0;
1353
1354  CFFList sqrfFactors;
1355  CFList tmp2;
1356  int k= 0;
1357  factors= uniFactors;
1358  CFFListIterator iter;
1359  for (CFListIterator i= factors; i.hasItem(); i++, k++)
1360  {
1361    tmp= 1;
1362    sqrfFactors= squarefreeFactorization (i.getItem(), alpha);
1363
1364    for (iter= sqrfFactors; iter.hasItem(); iter++)
1365    {
1366      tmp2.append (iter.getItem().factor());
1367      tmp *= iter.getItem().factor();
1368    }
1369    i.getItem()= tmp/Lc(tmp);
1370    bufSqrfFactors [k]= sqrfFactors;
1371  }
1372
1373  for (int i= 0; i < factors.length() - 1; i++)
1374  {
1375    for (k= i + 1; k < factors.length(); k++)
1376    {
1377      gcdFreeBasis (bufSqrfFactors [i], bufSqrfFactors[k]);
1378    }
1379  }
1380
1381  factors= CFList();
1382  for (int i= 0; i < uniFactors.length(); i++)
1383  {
1384    if (i == 0)
1385    {
1386      for (iter= bufSqrfFactors [i]; iter.hasItem(); iter++)
1387      {
1388        if (iter.getItem().factor().inCoeffDomain())
1389          continue;
1390        iter.getItem()= CFFactor (iter.getItem().factor()/
1391                                  Lc (iter.getItem().factor()),
1392                                  iter.getItem().exp());
1393        factors.append (iter.getItem().factor());
1394      }
1395    }
1396    else
1397    {
1398      for (iter= bufSqrfFactors [i]; iter.hasItem(); iter++)
1399      {
1400        if (iter.getItem().factor().inCoeffDomain())
1401          continue;
1402        iter.getItem()= CFFactor (iter.getItem().factor()/
1403                                  Lc (iter.getItem().factor()),
1404                                  iter.getItem().exp());
1405        if (!find (factors, iter.getItem().factor()))
1406          factors.append (iter.getItem().factor());
1407      }
1408    }
1409  }
1410
1411  test= prod (factors);
1412  tmp= evalSqrfPartF.getFirst() (evalPoint[0],2);
1413  if (test/Lc (test) != tmp/Lc (tmp))
1414    return 0;
1415  else
1416    return 1;
1417}
1418
1419CFList
1420precomputeLeadingCoeff (const CanonicalForm& LCF, const CFList& LCFFactors,
1421                        const Variable& alpha, const CFList& evaluation,
1422                        CFList* & differentSecondVarLCs, int lSecondVarLCs,
1423                        Variable& y
1424                       )
1425{
1426  y= Variable (1);
1427  if (LCF.inCoeffDomain())
1428  {
1429    CFList result;
1430    for (int i= 1; i <= LCFFactors.length() + 1; i++)
1431      result.append (1);
1432    return result;
1433  }
1434
1435  CFMap N;
1436  CanonicalForm F= compress (LCF, N);
1437  if (LCF.isUnivariate())
1438  {
1439    CFList result;
1440    int LCFLevel= LCF.level();
1441    bool found= false;
1442    if (LCFLevel == 2)
1443    {
1444    //bivariate leading coefficients are already the true leading coefficients
1445      result= LCFFactors;
1446      found= true;
1447    }
1448    else
1449    {
1450      CFListIterator j;
1451      for (int i= 0; i < lSecondVarLCs; i++)
1452      {
1453        for (j= differentSecondVarLCs[i]; j.hasItem(); j++)
1454        {
1455          if (j.getItem().level() == LCFLevel)
1456          {
1457            found= true;
1458            break;
1459          }
1460        }
1461        if (found)
1462        {
1463          result= differentSecondVarLCs [i];
1464          break;
1465        }
1466      }
1467      if (!found)
1468        result= LCFFactors;
1469    }
1470    if (found)
1471      result.insert (Lc (LCF));
1472    else
1473      result.append (LCF);
1474    return result;
1475  }
1476
1477  CFList factors= LCFFactors;
1478
1479  CFMap dummy;
1480  for (CFListIterator i= factors; i.hasItem(); i++)
1481    i.getItem()= compress (i.getItem(), dummy);
1482
1483  CanonicalForm sqrfPartF;
1484  CFFList * bufSqrfFactors= new CFFList [factors.length()];
1485  CFList evalSqrfPartF, bufFactors;
1486  CFArray evalPoint= CFArray (evaluation.length() - 1);
1487  CFListIterator iter= evaluation;
1488  for (int i= evaluation.length() - 2; i > -1; i--, iter++)
1489    evalPoint[i]= iter.getItem();
1490
1491  int pass= testFactors (F, factors, alpha, sqrfPartF,
1492                         bufFactors, bufSqrfFactors, evalSqrfPartF, evalPoint);
1493
1494  bool foundDifferent= false;
1495  Variable z, x= y;
1496  int j= 0;
1497  if (!pass)
1498  {
1499    int lev;
1500    // LCF is non-constant here
1501    for (int i= 1; i <= LCF.level(); i++)
1502    {
1503      if(degree (LCF, i) > 0)
1504      {
1505        lev= i - 1;
1506        break;
1507      }
1508    }
1509    CFList bufBufFactors;
1510    CanonicalForm bufF, swap;
1511    CFArray buf;
1512    for (int i= 0; i < lSecondVarLCs; i++)
1513    {
1514      if (!differentSecondVarLCs [i].isEmpty())
1515      {
1516        bool allConstant= true;
1517        for (iter= differentSecondVarLCs[i]; iter.hasItem(); iter++)
1518        {
1519          if (!iter.getItem().inCoeffDomain())
1520          {
1521            allConstant= false;
1522            y= Variable (iter.getItem().level());
1523          }
1524        }
1525        if (allConstant)
1526          continue;
1527
1528        bufFactors= differentSecondVarLCs [i];
1529        for (iter= bufFactors; iter.hasItem(); iter++)
1530          iter.getItem()= swapvar (iter.getItem(), x, y);
1531        bufF= F;
1532        z= Variable (y.level() - lev);
1533        bufF= swapvar (bufF, x, z);
1534        bufBufFactors= bufFactors;
1535        evalPoint= CFArray (evaluation.length() - 1);
1536        buf= CFArray (evaluation.length());
1537        iter= evaluation;
1538        int k= evaluation.length() - 1;
1539        for (; iter.hasItem(); iter++, k--)
1540          buf[k]= iter.getItem();
1541        swap= buf[z.level() - 1];
1542        buf[z.level() - 1]= buf[0];
1543        buf[0]= 0;
1544        int l= 0;
1545        for (k= 0; k < evaluation.length(); k++)
1546        {
1547          if (buf[k].isZero())
1548            continue;
1549          evalPoint[l]= buf[k];
1550          l++;
1551        }
1552        pass= testFactors (bufF, bufBufFactors, alpha, sqrfPartF, bufFactors,
1553                           bufSqrfFactors, evalSqrfPartF, evalPoint);
1554        if (pass)
1555        {
1556          foundDifferent= true;
1557          F= bufF;
1558          CFList l= factors;
1559          for (iter= l; iter.hasItem(); iter++)
1560            iter.getItem()= swapvar (iter.getItem(), x, y);
1561          differentSecondVarLCs [i]= l;
1562          j= i;
1563          break;
1564        }
1565        if (!pass && i == lSecondVarLCs - 1)
1566        {
1567          CFList result;
1568          result.append (LCF);
1569          for (int k= 1; k <= factors.length(); k++)
1570            result.append (LCF);
1571          y= Variable (1);
1572          delete [] bufSqrfFactors;
1573          return result;
1574        }
1575      }
1576    }
1577  }
1578  if (!pass)
1579  {
1580    CFList result;
1581    result.append (LCF);
1582    for (int k= 1; k <= factors.length(); k++)
1583      result.append (LCF);
1584    y= Variable (1);
1585    delete [] bufSqrfFactors;
1586    return result;
1587  }
1588  else
1589    factors= bufFactors;
1590
1591  bufFactors= factors;
1592  CFList evaluation2;
1593  if (y == x)
1594    evaluation2= evaluation;
1595  else
1596  {
1597    CanonicalForm tmp;
1598    evaluation2= evaluation;
1599    int i= evaluation.length() + 1;
1600    for (CFListIterator iter= evaluation2; iter.hasItem(); iter++, i--)
1601    {
1602      if (i == y.level())
1603      {
1604        tmp= iter.getItem();
1605        iter.getItem()= evaluation2.getLast();
1606        evaluation2.removeLast();
1607        evaluation2.append (tmp);
1608        break;
1609      }
1610    }
1611  }
1612
1613  CFList interMedResult;
1614  CanonicalForm oldSqrfPartF= sqrfPartF;
1615  sqrfPartF= shift2Zero (sqrfPartF, evalSqrfPartF, evaluation2, 1);
1616  if (factors.length() > 1)
1617  {
1618    CanonicalForm LC1= LC (oldSqrfPartF, 1);
1619    CFList leadingCoeffs;
1620    for (int i= 0; i < factors.length(); i++)
1621      leadingCoeffs.append (LC1);
1622
1623    CFList LC1eval= evaluateAtEval (LC1, evaluation2, 1);
1624    CFList oldFactors= factors;
1625    for (CFListIterator i= oldFactors; i.hasItem(); i++)
1626      i.getItem() *= LC1eval.getFirst()/Lc (i.getItem());
1627
1628    bool success= false;
1629    if (LucksWangSparseHeuristic (oldSqrfPartF*power (LC1, factors.length()-1),
1630                                  oldFactors, 1, leadingCoeffs, factors))
1631    {
1632      interMedResult= recoverFactors (oldSqrfPartF, factors);
1633      if (oldFactors.length() == interMedResult.length())
1634        success= true;
1635    }
1636    if (!success)
1637    {
1638      LC1= LC (evalSqrfPartF.getFirst(), 1);
1639
1640      CFArray leadingCoeffs= CFArray (factors.length());
1641      for (int i= 0; i < factors.length(); i++)
1642        leadingCoeffs[i]= LC1;
1643
1644      for (CFListIterator i= factors; i.hasItem(); i++)
1645      {
1646        i.getItem()= i.getItem() (x + evaluation2.getLast(), x);
1647        i.getItem() *= LC1 (0,2)/Lc (i.getItem());
1648      }
1649      factors.insert (1);
1650
1651      CanonicalForm
1652      newSqrfPartF= evalSqrfPartF.getFirst()*power (LC1, factors.length() - 2);
1653
1654      int liftBound= degree (newSqrfPartF,2) + 1;
1655
1656      CFMatrix M= CFMatrix (liftBound, factors.length() - 1);
1657      CFArray Pi;
1658      CFList diophant;
1659      henselLift122 (newSqrfPartF, factors, liftBound, Pi, diophant, M,
1660                     leadingCoeffs, false);
1661
1662      if (sqrfPartF.level() > 2)
1663      {
1664        int* liftBounds= new int [sqrfPartF.level() - 1];
1665        liftBounds [0]= liftBound;
1666        bool noOneToOne= false;
1667        CFList *leadingCoeffs2= new CFList [sqrfPartF.level()-2];
1668        LC1= LC (evalSqrfPartF.getLast(), 1);
1669        CFList LCs;
1670        for (int i= 0; i < factors.length(); i++)
1671          LCs.append (LC1);
1672        leadingCoeffs2 [sqrfPartF.level() - 3]= LCs;
1673        for (int i= sqrfPartF.level() - 1; i > 2; i--)
1674        {
1675          for (CFListIterator j= LCs; j.hasItem(); j++)
1676            j.getItem()= j.getItem() (0, i + 1);
1677          leadingCoeffs2 [i - 3]= LCs;
1678        }
1679        sqrfPartF *= power (LC1, factors.length()-1);
1680
1681        int liftBoundsLength= sqrfPartF.level() - 1;
1682        for (int i= 1; i < liftBoundsLength; i++)
1683          liftBounds [i]= degree (sqrfPartF, i + 2) + 1;
1684        evalSqrfPartF= evaluateAtZero (sqrfPartF);
1685        evalSqrfPartF.removeFirst();
1686        factors= nonMonicHenselLift (evalSqrfPartF, factors, leadingCoeffs2,
1687                 diophant, Pi, liftBounds, sqrfPartF.level() - 1, noOneToOne);
1688        delete [] leadingCoeffs2;
1689        delete [] liftBounds;
1690      }
1691      for (CFListIterator iter= factors; iter.hasItem(); iter++)
1692        iter.getItem()= reverseShift (iter.getItem(), evaluation2, 1);
1693
1694      interMedResult=
1695      recoverFactors (reverseShift(evalSqrfPartF.getLast(),evaluation2,1),
1696                      factors);
1697    }
1698  }
1699  else
1700  {
1701    factors= CFList (oldSqrfPartF);
1702    interMedResult= recoverFactors (oldSqrfPartF, factors);
1703  }
1704
1705  CFList result;
1706  CFFListIterator k;
1707  for (int i= 0; i < LCFFactors.length(); i++)
1708  {
1709    CanonicalForm tmp= 1;
1710    for (k= bufSqrfFactors[i]; k.hasItem(); k++)
1711    {
1712      int pos= findItem (bufFactors, k.getItem().factor());
1713      if (pos)
1714        tmp *= power (getItem (interMedResult, pos), k.getItem().exp());
1715    }
1716    result.append (tmp);
1717  }
1718
1719  for (CFListIterator i= result; i.hasItem(); i++)
1720  {
1721    F /= i.getItem();
1722    if (foundDifferent)
1723      i.getItem()= swapvar (i.getItem(), x, z);
1724    i.getItem()= N (i.getItem());
1725  }
1726
1727  if (foundDifferent)
1728  {
1729    CFList l= differentSecondVarLCs [j];
1730    for (CFListIterator i= l; i.hasItem(); i++)
1731      i.getItem()= swapvar (i.getItem(), y, z);
1732    differentSecondVarLCs [j]= l;
1733    F= swapvar (F, x, z);
1734  }
1735
1736  result.insert (N (F));
1737
1738  result= distributeContent (result, differentSecondVarLCs, lSecondVarLCs);
1739
1740  if (!result.getFirst().inCoeffDomain())
1741  {
1742    CFListIterator i= result;
1743    CanonicalForm tmp;
1744    if (foundDifferent)
1745      i.getItem()= swapvar (i.getItem(), Variable (2), y);
1746
1747    tmp= i.getItem();
1748
1749    i++;
1750    for (; i.hasItem(); i++)
1751    {
1752      if (foundDifferent)
1753        i.getItem()= swapvar (i.getItem(), Variable (2), y)*tmp;
1754      else
1755        i.getItem() *= tmp;
1756    }
1757  }
1758  else
1759    y= Variable (1);
1760
1761  delete [] bufSqrfFactors;
1762
1763  return result;
1764}
1765
1766void
1767evaluationWRTDifferentSecondVars (CFList*& Aeval, const CFList& evaluation,
1768                                  const CanonicalForm& A)
1769{
1770  CanonicalForm tmp;
1771  CFList tmp2;
1772  CFListIterator iter;
1773  for (int i= A.level(); i > 2; i--)
1774  {
1775    tmp= A;
1776    tmp2= CFList();
1777    iter= evaluation;
1778    bool preserveDegree= true;
1779    for (int j= A.level(); j > 1; j--, iter++)
1780    {
1781      if (j == i)
1782        continue;
1783      else
1784      {
1785        tmp= tmp (iter.getItem(), j);
1786        tmp2.insert (tmp);
1787        if ((degree (tmp, i) != degree (A, i)) ||
1788            (degree (tmp, 1) != degree (A, 1)))
1789        {
1790          preserveDegree= false;
1791          break;
1792        }
1793        if (!content(tmp).inCoeffDomain() || !content(tmp,1).inCoeffDomain())
1794        {
1795          preserveDegree= false;
1796          break;
1797        }
1798      }
1799    }
1800    if (preserveDegree)
1801      Aeval [i - 3]= tmp2;
1802    else
1803      Aeval [i - 3]= CFList();
1804  }
1805}
1806
1807#endif
1808
1809static inline
1810CanonicalForm prodEval (const CFList& l, const CanonicalForm& evalPoint,
1811                        const Variable& v)
1812{
1813  CanonicalForm result= 1;
1814  for (CFListIterator i= l; i.hasItem(); i++)
1815    result *= i.getItem() (evalPoint, v);
1816  return result;
1817}
1818
1819//recombine bivariate factors in case one bivariate factorization yields less
1820// factors than the other
1821CFList
1822recombination (const CFList& factors1, const CFList& factors2, int s, int thres,
1823               const CanonicalForm& evalPoint, const Variable& x)
1824{
1825  CFList T, S;
1826
1827  T= factors1;
1828  CFList result;
1829  CanonicalForm buf;
1830  int * v= new int [T.length()];
1831  for (int i= 0; i < T.length(); i++)
1832    v[i]= 0;
1833  bool nosubset= false;
1834  CFArray TT;
1835  TT= copy (factors1);
1836  while (T.length() >= 2*s && s <= thres)
1837  {
1838    while (nosubset == false) 
1839    {
1840      if (T.length() == s) 
1841      {
1842        delete [] v;
1843        result.append (prod (T));
1844        return result;
1845      }
1846      S= subset (v, s, TT, nosubset);
1847      if (nosubset) break;
1848      buf= prodEval (S, evalPoint, x);
1849      buf /= Lc (buf);
1850      if (find (factors2, buf))
1851      {
1852        T= Difference (T, S);
1853        result.append (prod (S));
1854        TT= copy (T);
1855        indexUpdate (v, s, T.length(), nosubset);
1856        if (nosubset) break;
1857      }
1858    }
1859    s++;
1860    if (T.length() < 2*s || T.length() == s) 
1861    {
1862      delete [] v;
1863      result.append (prod (T));
1864      return result;
1865    }
1866    for (int i= 0; i < T.length(); i++)
1867      v[i]= 0;
1868    nosubset= false;
1869  }
1870
1871  delete [] v;
1872  if (T.length() < 2*s)
1873  {
1874    result.append (prod (T));
1875    return result;
1876  }
1877
1878  return result;
1879}
1880
1881#ifdef HAVE_NTL
1882void
1883factorizationWRTDifferentSecondVars (const CanonicalForm& A, CFList*& Aeval,
1884                                     const ExtensionInfo& info,
1885                                     int& minFactorsLength, bool& irred)
1886{
1887  Variable x= Variable (1);
1888  minFactorsLength= 0;
1889  irred= false;
1890  CFList factors;
1891  Variable v;
1892  for (int j= 0; j < A.level() - 2; j++)
1893  {
1894    if (!Aeval[j].isEmpty())
1895    {
1896      v= Variable (Aeval[j].getFirst().level());
1897      if (CFFactory::gettype() == GaloisFieldDomain)
1898        factors= GFBiSqrfFactorize (Aeval[j].getFirst());
1899      else if (info.getAlpha().level() == 1)
1900        factors= FpBiSqrfFactorize (Aeval[j].getFirst());
1901      else
1902        factors= FqBiSqrfFactorize (Aeval[j].getFirst(), info.getAlpha());
1903
1904      factors.removeFirst();
1905      if (minFactorsLength == 0)
1906        minFactorsLength= factors.length();
1907      else
1908        minFactorsLength= tmin (minFactorsLength, factors.length());
1909
1910      if (factors.length() == 1)
1911      {
1912        irred= true;
1913        return;
1914      }
1915      sortList (factors, x);
1916      Aeval [j]= factors;
1917    }
1918  }
1919}
1920
1921void getLeadingCoeffs (const CanonicalForm& A, CFList*& Aeval,
1922                       const CFList& uniFactors, const CFList& evaluation
1923                      )
1924{
1925  CanonicalForm evalPoint;
1926  int i;
1927  CFListIterator iter, iter2;
1928  Variable v;
1929  CFList l, LCs, buf;
1930  int pos;
1931  for (int j= 0; j < A.level() - 2; j++)
1932  {
1933    if (!Aeval[j].isEmpty())
1934    {
1935      i= A.level();
1936      for (iter= evaluation; iter.hasItem(); iter++, i--)
1937      {
1938        if (i == Aeval[j].getFirst().level())
1939        {
1940          evalPoint= iter.getItem();
1941          break;
1942        }
1943      }
1944
1945      v= Variable (i);
1946      if (Aeval[j].length() > uniFactors.length())
1947        Aeval[j]= recombination (Aeval[j], uniFactors, 1,
1948                                 Aeval[j].length() - uniFactors.length() + 1,
1949                                 evalPoint, v);
1950
1951      l= CFList();
1952      buf= buildUniFactors (Aeval[j], evalPoint, v);
1953      for (iter= uniFactors; iter.hasItem(); iter++)
1954      {
1955        pos= findItem (buf, iter.getItem());
1956        if (pos)
1957          l.append (getItem (Aeval[j], pos));
1958      }
1959      Aeval [j]= l;
1960
1961      LCs= CFList();
1962      for (iter= Aeval[j]; iter.hasItem(); iter++)
1963        LCs.append (LC (iter.getItem(), 1));
1964      normalize (LCs);
1965      Aeval[j]= LCs;
1966    }
1967  }
1968}
1969
1970CFList
1971buildUniFactors (const CFList& biFactors, const CanonicalForm& evalPoint,
1972                 const Variable& y)
1973{
1974  CFList result;
1975  CanonicalForm tmp;
1976  for (CFListIterator i= biFactors; i.hasItem(); i++)
1977  {
1978    tmp= mod (i.getItem(), y - evalPoint);
1979    tmp /= Lc (tmp);
1980    result.append (tmp);
1981  }
1982  return result;
1983}
1984
1985void refineBiFactors (const CanonicalForm& A, CFList& biFactors,
1986                      CFList* const& Aeval, const CFList& evaluation,
1987                      int minFactorsLength)
1988{
1989  CFListIterator iter;
1990  CanonicalForm evalPoint;
1991  int i;
1992  Variable v;
1993  Variable y= Variable (2);
1994  CFList list;
1995  for (int j= 0; j < A.level() - 2; j++)
1996  {
1997    if (Aeval[j].length() == minFactorsLength)
1998    {
1999      i= A.level();
2000
2001      for (iter= evaluation; iter.hasItem(); iter++, i--)
2002      {
2003        if (i == Aeval[j].getFirst().level())
2004        {
2005          evalPoint= iter.getItem();
2006          break;
2007        }
2008      }
2009
2010      v= Variable (i);
2011      list= buildUniFactors (Aeval[j], evalPoint, v);
2012
2013      biFactors= recombination (biFactors, list, 1,
2014                                biFactors.length() - list.length() + 1,
2015                                evaluation.getLast(), y);
2016      return;
2017    }
2018  }
2019}
2020
2021void prepareLeadingCoeffs (CFList*& LCs, int n, const CFList& leadingCoeffs,
2022                           const CFList& biFactors, const CFList& evaluation)
2023{
2024  CFList l= leadingCoeffs;
2025  LCs [n-3]= l;
2026  CFListIterator j;
2027  CFListIterator iter= evaluation;
2028  for (int i= n - 1; i > 2; i--, iter++)
2029  {
2030    for (j= l; j.hasItem(); j++)
2031      j.getItem()= j.getItem() (iter.getItem(), i + 1);
2032    LCs [i - 3]= l;
2033  }
2034  l= LCs [0];
2035  for (CFListIterator i= l; i.hasItem(); i++)
2036    i.getItem()= i.getItem() (iter.getItem(), 3);
2037  CFListIterator ii= biFactors;
2038  CFList normalizeFactor;
2039  for (CFListIterator i= l; i.hasItem(); i++, ii++)
2040    normalizeFactor.append (Lc (LC (ii.getItem(), 1))/Lc (i.getItem()));
2041  for (int i= 0; i < n-2; i++)
2042  {
2043    ii= normalizeFactor;
2044    for (j= LCs [i]; j.hasItem(); j++, ii++)
2045      j.getItem() *= ii.getItem();
2046  }
2047}
2048
2049CFList recoverFactors (const CanonicalForm& F, const CFList& factors)
2050{
2051  CFList result;
2052  CanonicalForm tmp, tmp2;
2053  CanonicalForm G= F;
2054  for (CFListIterator i= factors; i.hasItem(); i++)
2055  {
2056    tmp= i.getItem()/content (i.getItem(), 1);
2057    if (fdivides (tmp, G, tmp2))
2058    {
2059      G= tmp2;
2060      result.append (tmp);
2061    }
2062  }
2063  return result;
2064}
2065
2066CFList recoverFactors (const CanonicalForm& F, const CFList& factors,
2067                       const CFList& evaluation)
2068{
2069  CFList result;
2070  CanonicalForm tmp, tmp2;
2071  CanonicalForm G= F;
2072  for (CFListIterator i= factors; i.hasItem(); i++)
2073  {
2074    tmp= reverseShift (i.getItem(), evaluation);
2075    tmp /= content (tmp, 1);
2076    if (fdivides (tmp, G, tmp2))
2077    {
2078      G= tmp2;
2079      result.append (tmp);
2080    }
2081  }
2082  return result;
2083}
2084
2085CFList
2086extNonMonicFactorRecombination (const CFList& factors, const CanonicalForm& F,
2087                                const ExtensionInfo& info)
2088{
2089  Variable alpha= info.getAlpha();
2090  Variable beta= info.getBeta();
2091  CanonicalForm gamma= info.getGamma();
2092  CanonicalForm delta= info.getDelta();
2093  int k= info.getGFDegree();
2094  CFList source, dest;
2095
2096  int degMipoBeta= 1;
2097  if (!k && beta != Variable(1))
2098    degMipoBeta= degree (getMipo (beta));
2099
2100  CFList T, S;
2101  T= factors;
2102  int s= 1;
2103  CFList result;
2104  CanonicalForm quot, buf= F;
2105
2106  CanonicalForm g;
2107  CanonicalForm buf2;
2108  int * v= new int [T.length()];
2109  for (int i= 0; i < T.length(); i++)
2110    v[i]= 0;
2111  bool noSubset= false;
2112  CFArray TT;
2113  TT= copy (factors);
2114  bool recombination= false;
2115  bool trueFactor= false;
2116  while (T.length() >= 2*s)
2117  {
2118    while (noSubset == false)
2119    {
2120      if (T.length() == s)
2121      {
2122        delete [] v;
2123        if (recombination)
2124        {
2125          g= prod (T);
2126          T.removeFirst();
2127          result.append (g/myContent (g));
2128          g /= Lc (g);
2129          appendTestMapDown (result, g, info, source, dest);
2130          return result;
2131        }
2132        else
2133          return CFList (buf);
2134      }
2135
2136      S= subset (v, s, TT, noSubset);
2137      if (noSubset) break;
2138
2139      g= prod (S);
2140      g /= myContent (g);
2141      if (fdivides (g, buf, quot))
2142      {
2143        buf2= g;
2144        buf2 /= Lc (buf2);
2145        if (!k && beta.level() == 1)
2146        {
2147          if (degree (buf2, alpha) < degMipoBeta)
2148          {
2149            appendTestMapDown (result, buf2, info, source, dest);
2150            buf= quot;
2151            recombination= true;
2152            trueFactor= true;
2153          }
2154        }
2155        else
2156        {
2157          if (!isInExtension (buf2, gamma, k, delta, source, dest))
2158          {
2159            appendTestMapDown (result, buf2, info, source, dest);
2160            buf= quot;
2161            recombination= true;
2162            trueFactor= true;
2163          }
2164        }
2165        if (trueFactor)
2166        {
2167          T= Difference (T, S);
2168
2169          if (T.length() < 2*s || T.length() == s)
2170          {
2171            delete [] v;
2172            buf /= Lc (buf);
2173            appendTestMapDown (result, buf, info, source, dest);
2174            return result;
2175          }
2176          trueFactor= false;
2177          TT= copy (T);
2178          indexUpdate (v, s, T.length(), noSubset);
2179          if (noSubset) break;
2180        }
2181      }
2182    }
2183    s++;
2184    if (T.length() < 2*s || T.length() == s)
2185    {
2186      delete [] v;
2187      appendTestMapDown (result, buf, info, source, dest);
2188      return result;
2189    }
2190    for (int i= 0; i < T.length(); i++)
2191      v[i]= 0;
2192    noSubset= false;
2193  }
2194  if (T.length() < 2*s)
2195    appendMapDown (result, F, info, source, dest);
2196
2197  delete [] v;
2198  return result;
2199}
2200
2201CFList
2202extFactorize (const CanonicalForm& F, const ExtensionInfo& info);
2203
2204CFList
2205multiFactorize (const CanonicalForm& F, const ExtensionInfo& info)
2206{
2207
2208  if (F.inCoeffDomain())
2209    return CFList (F);
2210
2211  // compress and find main Variable
2212  CFMap N;
2213  CanonicalForm A= myCompress (F, N);
2214
2215  A /= Lc (A); // make monic
2216
2217  Variable alpha= info.getAlpha();
2218  Variable beta= info.getBeta();
2219  CanonicalForm gamma= info.getGamma();
2220  CanonicalForm delta= info.getDelta();
2221  bool extension= info.isInExtension();
2222  bool GF= (CFFactory::gettype() == GaloisFieldDomain);
2223  //univariate case
2224  if (F.isUnivariate())
2225  {
2226    if (extension == false)
2227      return uniFactorizer (F, alpha, GF);
2228    else
2229    {
2230      CFList source, dest;
2231      A= mapDown (F, info, source, dest);
2232      return uniFactorizer (A, beta, GF);
2233    }
2234  }
2235
2236  //bivariate case
2237  if (A.level() == 2)
2238  {
2239    CFList buf= biFactorize (F, info);
2240    return buf;
2241  }
2242
2243  Variable x= Variable (1);
2244  Variable y= Variable (2);
2245
2246  // remove content
2247  CFList contentAi;
2248  CanonicalForm lcmCont= lcmContent (A, contentAi);
2249  A /= lcmCont;
2250
2251  // trivial after content removal
2252  CFList contentAFactors;
2253  if (A.inCoeffDomain())
2254  {
2255    for (CFListIterator i= contentAi; i.hasItem(); i++)
2256    {
2257      if (i.getItem().inCoeffDomain())
2258        continue;
2259      else
2260      {
2261        lcmCont /= i.getItem();
2262        contentAFactors=
2263        Union (multiFactorize (lcmCont, info),
2264               multiFactorize (i.getItem(), info));
2265        break;
2266      }
2267    }
2268    decompress (contentAFactors, N);
2269    normalize (contentAFactors);
2270    return contentAFactors;
2271  }
2272
2273  // factorize content
2274  contentAFactors= multiFactorize (lcmCont, info);
2275
2276  // univariate after content removal
2277  CFList factors;
2278  if (A.isUnivariate ())
2279  {
2280    factors= uniFactorizer (A, alpha, GF);
2281    append (factors, contentAFactors);
2282    decompress (factors, N);
2283    return factors;
2284  }
2285
2286  // check main variable
2287  int swapLevel= 0;
2288  CanonicalForm derivZ;
2289  CanonicalForm gcdDerivZ;
2290  CanonicalForm bufA= A;
2291  Variable z;
2292  for (int i= 1; i <= A.level(); i++)
2293  {
2294    z= Variable (i);
2295    derivZ= deriv (bufA, z);
2296    if (derivZ.isZero())
2297    {
2298      if (i == 1)
2299        swapLevel= 1;
2300      else
2301        continue;
2302    }
2303    else
2304    {
2305      if (swapLevel == 1)
2306      {
2307        swapLevel= i;
2308        bufA= swapvar (A, x, z);
2309      }
2310      gcdDerivZ= gcd (bufA, derivZ);
2311      if (degree (gcdDerivZ) > 0 && !derivZ.isZero())
2312      {
2313        CanonicalForm g= bufA/gcdDerivZ;
2314        CFList factorsG=
2315        Union (multiFactorize (g, info),
2316               multiFactorize (gcdDerivZ, info));
2317        appendSwapDecompress (factorsG, contentAFactors, N, swapLevel, x);
2318        normalize (factorsG);
2319        return factorsG;
2320      }
2321      else
2322      {
2323        A= bufA;
2324        break;
2325      }
2326    }
2327  }
2328
2329
2330  CFList Aeval, list, evaluation, bufEvaluation, bufAeval;
2331  bool fail= false;
2332  int swapLevel2= 0;
2333  int level;
2334  int factorNums= 3;
2335  CanonicalForm bivarEval;
2336  CFList biFactors, bufBiFactors;
2337  CanonicalForm evalPoly;
2338  int lift, bufLift;
2339  double logarithm= (double) ilog2 (totaldegree (A));
2340  logarithm /= log2exp;
2341  logarithm= ceil (logarithm);
2342  if (factorNums < (int) logarithm)
2343    factorNums= (int) logarithm;
2344  CFList* bufAeval2= new CFList [A.level() - 2];
2345  CFList* Aeval2= new CFList [A.level() - 2];
2346  int counter;
2347  int differentSecondVar= 0;
2348  // several bivariate factorizations
2349  for (int i= 0; i < factorNums; i++)
2350  {
2351    counter= 0;
2352    bufA= A;
2353    bufAeval= CFList();
2354    bufEvaluation= evalPoints (bufA, bufAeval, alpha, list, GF, fail);
2355    evalPoly= 0;
2356
2357    if (fail && (i == 0))
2358    {
2359      if (!swapLevel)
2360        level= 2;
2361      else
2362        level= swapLevel + 1;
2363
2364      CanonicalForm g;
2365      swapLevel2= newMainVariableSearch (A, Aeval, evaluation, alpha, level, g);
2366
2367      if (!swapLevel2) // need to pass to an extension
2368      {
2369        factors= extFactorize (A, info);
2370        appendSwapDecompress (factors, contentAFactors, N, swapLevel, x);
2371        normalize (factors);
2372        delete [] bufAeval2;
2373        delete [] Aeval2;
2374        return factors;
2375      }
2376      else
2377      {
2378        if (swapLevel2 == -1)
2379        {
2380          CFList factorsG=
2381          Union (multiFactorize (g, info),
2382                 multiFactorize (A/g, info));
2383          appendSwapDecompress (factorsG, contentAFactors, N, swapLevel, x);
2384          normalize (factorsG);
2385          delete [] bufAeval2;
2386          delete [] Aeval2;
2387          return factorsG;
2388        }
2389        fail= false;
2390        bufAeval= Aeval;
2391        bufA= A;
2392        bufEvaluation= evaluation;
2393      }
2394    }
2395    else if (fail && (i > 0))
2396      break;
2397
2398    bivarEval= bufEvaluation.getLast();
2399
2400    evaluationWRTDifferentSecondVars (bufAeval2, bufEvaluation, A);
2401
2402    for (int j= 0; j < A.level() - 2; j++)
2403    {
2404      if (!bufAeval2[j].isEmpty())
2405        counter++;
2406    }
2407
2408    bufLift= degree (A, y) + 1 + degree (LC(A, x), y);
2409
2410    TIMING_START (fac_bi_factorizer);
2411    if (!GF && alpha.level() == 1)
2412      bufBiFactors= FpBiSqrfFactorize (bufAeval.getFirst());
2413    else if (GF)
2414      bufBiFactors= GFBiSqrfFactorize (bufAeval.getFirst());
2415    else
2416      bufBiFactors= FqBiSqrfFactorize (bufAeval.getFirst(), alpha);
2417    TIMING_END_AND_PRINT (fac_bi_factorizer,
2418                          "time for bivariate factorization: ");
2419    bufBiFactors.removeFirst();
2420
2421    if (bufBiFactors.length() == 1)
2422    {
2423      if (extension)
2424      {
2425        CFList source, dest;
2426        A= mapDown (A, info, source, dest);
2427      }
2428      factors.append (A);
2429      appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2430                            swapLevel2, x);
2431      normalize (factors);
2432      delete [] bufAeval2;
2433      delete [] Aeval2;
2434      return factors;
2435    }
2436
2437    if (i == 0)
2438    {
2439      Aeval= bufAeval;
2440      evaluation= bufEvaluation;
2441      biFactors= bufBiFactors;
2442      lift= bufLift;
2443      for (int j= 0; j < A.level() - 2; j++)
2444        Aeval2 [j]= bufAeval2 [j];
2445      differentSecondVar= counter;
2446    }
2447    else
2448    {
2449      if (bufBiFactors.length() < biFactors.length() ||
2450          ((bufLift < lift) && (bufBiFactors.length() == biFactors.length())) ||
2451          counter > differentSecondVar)
2452      {
2453        Aeval= bufAeval;
2454        evaluation= bufEvaluation;
2455        biFactors= bufBiFactors;
2456        lift= bufLift;
2457        for (int j= 0; j < A.level() - 2; j++)
2458          Aeval2 [j]= bufAeval2 [j];
2459        differentSecondVar= counter;
2460      }
2461    }
2462    int k= 0;
2463    for (CFListIterator j= bufEvaluation; j.hasItem(); j++, k++)
2464      evalPoly += j.getItem()*power (x, k);
2465    list.append (evalPoly);
2466  }
2467
2468  delete [] bufAeval2;
2469
2470  sortList (biFactors, x);
2471
2472  int minFactorsLength;
2473  bool irred= false;
2474  factorizationWRTDifferentSecondVars (A, Aeval2, info, minFactorsLength, irred);
2475
2476  if (irred)
2477  {
2478    if (extension)
2479    {
2480      CFList source, dest;
2481      A= mapDown (A, info, source, dest);
2482    }
2483    factors.append (A);
2484    appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2485                          swapLevel2, x);
2486    normalize (factors);
2487    delete [] Aeval2;
2488    return factors;
2489  }
2490
2491  if (minFactorsLength == 0)
2492    minFactorsLength= biFactors.length();
2493  else if (biFactors.length() > minFactorsLength)
2494    refineBiFactors (A, biFactors, Aeval2, evaluation, minFactorsLength);
2495  minFactorsLength= tmin (minFactorsLength, biFactors.length());
2496
2497  if (differentSecondVar == A.level() - 2)
2498  {
2499    bool zeroOccured= false;
2500    for (CFListIterator iter= evaluation; iter.hasItem(); iter++)
2501    {
2502      if (iter.getItem().isZero())
2503      {
2504        zeroOccured= true;
2505        break;
2506      }
2507    }
2508    if (!zeroOccured)
2509    {
2510      factors= sparseHeuristic (A, biFactors, Aeval2, evaluation, minFactorsLength);
2511      if (factors.length() == biFactors.length())
2512      {
2513        if (extension)
2514          factors= extNonMonicFactorRecombination (factors, A, info);
2515
2516        appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2517                              swapLevel2, x);
2518        normalize (factors);
2519        delete [] Aeval2;
2520        return factors;
2521      }
2522      else
2523        factors= CFList();
2524      //TODO case where factors.length() > 0
2525    }
2526  }
2527
2528  CFList uniFactors= buildUniFactors (biFactors, evaluation.getLast(), y);
2529
2530  CFList * oldAeval= new CFList [A.level() - 2]; //TODO use bufAeval2 for this
2531  for (int i= 0; i < A.level() - 2; i++)
2532    oldAeval[i]= Aeval2[i];
2533
2534  getLeadingCoeffs (A, Aeval2, uniFactors, evaluation);
2535
2536  CFList biFactorsLCs;
2537  for (CFListIterator i= biFactors; i.hasItem(); i++)
2538    biFactorsLCs.append (LC (i.getItem(), 1));
2539
2540  Variable v;
2541  CFList leadingCoeffs= precomputeLeadingCoeff (LC (A, 1), biFactorsLCs, alpha,
2542                                          evaluation, Aeval2, A.level() - 2, v);
2543
2544  if (v.level() != 1)
2545  {
2546    A= swapvar (A, y, v);
2547    for (int i= 0; i < A.level() - 2; i++)
2548    {
2549      if (oldAeval[i].isEmpty())
2550        continue;
2551      if (oldAeval[i].getFirst().level() == v.level())
2552      {
2553        biFactors= CFList();
2554        for (CFListIterator iter= oldAeval [i]; iter.hasItem(); iter++)
2555          biFactors.append (swapvar (iter.getItem(), v, y));
2556      }
2557    }
2558    int i= A.level();
2559    CanonicalForm evalPoint;
2560    for (CFListIterator iter= evaluation; iter.hasItem(); iter++, i--)
2561    {
2562      if (i == v.level())
2563      {
2564        evalPoint= iter.getItem();
2565        iter.getItem()= evaluation.getLast();
2566        evaluation.removeLast();
2567        evaluation.append (evalPoint);
2568        break;
2569      }
2570    }
2571  }
2572
2573  CFListIterator iter;
2574  CanonicalForm oldA= A;
2575  CFList oldBiFactors= biFactors;
2576  if (!leadingCoeffs.getFirst().inCoeffDomain())
2577  {
2578    CanonicalForm tmp= power (leadingCoeffs.getFirst(), biFactors.length() - 1);
2579    A *= tmp;
2580    tmp= leadingCoeffs.getFirst();
2581    iter= evaluation;
2582    for (int i= A.level(); i > 2; i--, iter++)
2583      tmp= tmp (iter.getItem(), i);
2584    if (!tmp.inCoeffDomain())
2585    {
2586      for (CFListIterator i= biFactors; i.hasItem(); i++)
2587      {
2588        i.getItem() *= tmp/LC (i.getItem(), 1);
2589        i.getItem() /= Lc (i.getItem());
2590      }
2591    }
2592  }
2593
2594  leadingCoeffs.removeFirst();
2595
2596  //prepare leading coefficients
2597  CFList* leadingCoeffs2= new CFList [A.level() - 2];
2598  prepareLeadingCoeffs (leadingCoeffs2, A.level(), leadingCoeffs, biFactors,
2599                        evaluation);
2600
2601  Aeval= evaluateAtEval (A, evaluation, 2);
2602  CanonicalForm hh= Lc (Aeval.getFirst());
2603  for (iter= Aeval; iter.hasItem(); iter++)
2604    iter.getItem() /= hh;
2605
2606  A /= hh;
2607
2608  if (LucksWangSparseHeuristic (A, biFactors, 2, leadingCoeffs2 [A.level() - 3],
2609      factors))
2610  {
2611    int check= factors.length();
2612    factors= recoverFactors (A, factors);
2613
2614    if (check == factors.length())
2615    {
2616      if (extension)
2617        factors= extNonMonicFactorRecombination (factors, A, info);
2618
2619      appendSwapDecompress (factors, contentAFactors, N, swapLevel,
2620                            swapLevel2, x);
2621      normalize (factors);
2622      delete [] Aeval2;
2623      return factors;
2624    }
2625    else
2626      factors= CFList();
2627    //TODO handle this case
2628  }
2629
2630  A= shift2Zero (A, Aeval, evaluation);
2631
2632  for (iter= biFactors; iter.hasItem(); iter++)
2633    iter.getItem()= iter.getItem () (y + evaluation.getLast(), y);
2634
2635  for (int i= 0; i < A.level() - 2; i++)
2636  {
2637    if (i != A.level() - 3)
2638      leadingCoeffs2[i]= CFList();
2639  }
2640  for (iter= leadingCoeffs2[A.level() - 3]; iter.hasItem(); iter++)
2641  {
2642    iter.getItem()= shift2Zero (iter.getItem(), list, evaluation);
2643    for (int i= A.level() - 4; i > -1; i--)
2644    {
2645      if (i + 1 == A.level() - 3)
2646        leadingCoeffs2[i].append (iter.getItem() (0, i + 4));
2647      else
2648        leadingCoeffs2[i].append (leadingCoeffs2[i+1].getLast() (0, i + 4));
2649    }
2650  }
2651
2652  CFArray Pi;
2653  CFList diophant;
2654  int* liftBounds= new int [A.level() - 1];
2655  int liftBoundsLength= A.level() - 1;
2656  for (int i= 0; i < liftBoundsLength; i++)
2657    liftBounds [i]= degree (A, i + 2) + 1;
2658
2659  Aeval.removeFirst();
2660  bool noOneToOne= false;
2661  factors= nonMonicHenselLift (Aeval, biFactors, leadingCoeffs2, diophant,
2662                               Pi, liftBounds, liftBoundsLength, noOneToOne);
2663
2664  if (!noOneToOne)
2665  {
2666    int check= factors.length();
2667    A= oldA;
2668    factors= recoverFactors (A, factors, evaluation);
2669    if (check != factors.length())
2670      noOneToOne= true;
2671
2672    if (extension && !noOneToOne)
2673      factors= extNonMonicFactorRecombination (factors, A, info);
2674  }
2675  if (noOneToOne)
2676  {
2677    A= shift2Zero (oldA, Aeval, evaluation);
2678    biFactors= oldBiFactors;
2679    for (iter= biFactors; iter.hasItem(); iter++)
2680      iter.getItem()= iter.getItem () (y + evaluation.getLast(), y);
2681    CanonicalForm LCA= LC (Aeval.getFirst(), 1);
2682    CanonicalForm yToLift= power (y, lift);
2683    CFListIterator i= biFactors;
2684    lift= degree (i.getItem(), 2) + degree (LC (i.getItem(), 1)) + 1;
2685    i++;
2686
2687    for (; i.hasItem(); i++)
2688      lift= tmax (lift, degree (i.getItem(), 2) + degree (LC (i.getItem(), 1)) + 1);
2689
2690    lift= tmax (degree (Aeval.getFirst() , 2) + 1, lift);
2691
2692    i= biFactors;
2693    yToLift= power (y, lift);
2694    CanonicalForm dummy;
2695    for (; i.hasItem(); i++)
2696    {
2697      LCA= LC (i.getItem(), 1);
2698      extgcd (LCA, yToLift, LCA, dummy);
2699      i.getItem()= mod (i.getItem()*LCA, yToLift);
2700    }
2701
2702    liftBoundsLength= F.level() - 1;
2703    liftBounds= liftingBounds (A, lift);
2704
2705    CFList MOD;
2706    bool earlySuccess;
2707    CFList earlyFactors;
2708    TIMING_START (fac_hensel_lift);
2709    CFList liftedFactors= henselLiftAndEarly
2710                          (A, MOD, liftBounds, earlySuccess, earlyFactors,
2711                           Aeval, biFactors, evaluation, info);
2712    TIMING_END_AND_PRINT (fac_hensel_lift, "time for hensel lifting: ");
2713
2714    if (!extension)
2715    {
2716      TIMING_START (fac_factor_recombination);
2717      factors= factorRecombination (A, liftedFactors, MOD);
2718      TIMING_END_AND_PRINT (fac_factor_recombination,
2719                            "time for factor recombination: ");
2720    }
2721    else
2722    {
2723      TIMING_START (fac_factor_recombination);
2724      factors= extFactorRecombination (liftedFactors, A, MOD, info, evaluation);
2725      TIMING_END_AND_PRINT (fac_factor_recombination,
2726                            "time for factor recombination: ");
2727    }
2728
2729    if (earlySuccess)
2730      factors= Union (factors, earlyFactors);
2731    if (!extension)
2732    {
2733      for (CFListIterator i= factors; i.hasItem(); i++)
2734      {
2735        int kk= Aeval.getLast().level();
2736        for (CFListIterator j= evaluation; j.hasItem(); j++, kk--)
2737        {
2738          if (i.getItem().level() < kk)
2739            continue;
2740          i.getItem()= i.getItem() (Variable (kk) - j.getItem(), kk);
2741        }
2742      }
2743    }
2744  }
2745
2746  if (v.level() != 1)
2747  {
2748    for (CFListIterator iter= factors; iter.hasItem(); iter++)
2749      iter.getItem()= swapvar (iter.getItem(), v, y);
2750  }
2751
2752  swap (factors, swapLevel, swapLevel2, x);
2753  append (factors, contentAFactors);
2754  decompress (factors, N);
2755  normalize (factors);
2756
2757  delete[] liftBounds;
2758
2759  return factors;
2760}
2761
2762/// multivariate factorization over an extension of the initial field
2763CFList
2764extFactorize (const CanonicalForm& F, const ExtensionInfo& info)
2765{
2766  CanonicalForm A= F;
2767
2768  Variable alpha= info.getAlpha();
2769  Variable beta= info.getBeta();
2770  int k= info.getGFDegree();
2771  char cGFName= info.getGFName();
2772  CanonicalForm delta= info.getDelta();
2773  bool GF= (CFFactory::gettype() == GaloisFieldDomain);
2774  Variable w= Variable (1);
2775
2776  CFList factors;
2777  if (!GF && alpha == w)  // we are in F_p
2778  {
2779    CFList factors;
2780    bool extension= true;
2781    int p= getCharacteristic();
2782    if (p*p < (1<<16)) // pass to GF if possible
2783    {
2784      setCharacteristic (getCharacteristic(), 2, 'Z');
2785      ExtensionInfo info= ExtensionInfo (extension);
2786      A= A.mapinto();
2787      factors= multiFactorize (A, info);
2788
2789      Variable vBuf= rootOf (gf_mipo);
2790      setCharacteristic (getCharacteristic());
2791      for (CFListIterator j= factors; j.hasItem(); j++)
2792        j.getItem()= GF2FalphaRep (j.getItem(), vBuf);
2793    }
2794    else  // not able to pass to GF, pass to F_p(\alpha)
2795    {
2796      CanonicalForm mipo= randomIrredpoly (2, w);
2797      Variable v= rootOf (mipo);
2798      ExtensionInfo info= ExtensionInfo (v);
2799      factors= multiFactorize (A, info);
2800    }
2801    return factors;
2802  }
2803  else if (!GF && (alpha != w)) // we are in F_p(\alpha)
2804  {
2805    if (k == 1) // need factorization over F_p
2806    {
2807      int extDeg= degree (getMipo (alpha));
2808      extDeg++;
2809      CanonicalForm mipo= randomIrredpoly (extDeg + 1, w);
2810      Variable v= rootOf (mipo);
2811      ExtensionInfo info= ExtensionInfo (v);
2812      factors= biFactorize (A, info);
2813    }
2814    else
2815    {
2816      if (beta == w)
2817      {
2818        Variable v= chooseExtension (alpha, beta, k);
2819        CanonicalForm primElem, imPrimElem;
2820        bool primFail= false;
2821        Variable vBuf;
2822        primElem= primitiveElement (alpha, vBuf, primFail);
2823        ASSERT (!primFail, "failure in integer factorizer");
2824        if (primFail)
2825          ; //ERROR
2826        else
2827          imPrimElem= mapPrimElem (primElem, vBuf, v);
2828
2829        CFList source, dest;
2830        CanonicalForm bufA= mapUp (A, alpha, v, primElem, imPrimElem,
2831                                   source, dest);
2832        ExtensionInfo info= ExtensionInfo (v, alpha, imPrimElem, primElem);
2833        factors= biFactorize (bufA, info);
2834      }
2835      else
2836      {
2837        Variable v= chooseExtension (alpha, beta, k);
2838        CanonicalForm primElem, imPrimElem;
2839        bool primFail= false;
2840        Variable vBuf;
2841        ASSERT (!primFail, "failure in integer factorizer");
2842        if (primFail)
2843          ; //ERROR
2844        else
2845          imPrimElem= mapPrimElem (delta, beta, v);
2846
2847        CFList source, dest;
2848        CanonicalForm bufA= mapDown (A, info, source, dest);
2849        source= CFList();
2850        dest= CFList();
2851        bufA= mapUp (bufA, beta, v, delta, imPrimElem, source, dest);
2852        ExtensionInfo info= ExtensionInfo (v, beta, imPrimElem, delta);
2853        factors= biFactorize (bufA, info);
2854      }
2855    }
2856    return factors;
2857  }
2858  else // we are in GF (p^k)
2859  {
2860    int p= getCharacteristic();
2861    int extensionDeg= getGFDegree();
2862    bool extension= true;
2863    if (k == 1) // need factorization over F_p
2864    {
2865      extensionDeg++;
2866      if (pow ((double) p, (double) extensionDeg) < (1<<16))
2867      // pass to GF(p^k+1)
2868      {
2869        setCharacteristic (p);
2870        Variable vBuf= rootOf (gf_mipo);
2871        A= GF2FalphaRep (A, vBuf);
2872        setCharacteristic (p, extensionDeg, 'Z');
2873        ExtensionInfo info= ExtensionInfo (extension);
2874        factors= multiFactorize (A.mapinto(), info);
2875      }
2876      else // not able to pass to another GF, pass to F_p(\alpha)
2877      {
2878        setCharacteristic (p);
2879        Variable vBuf= rootOf (gf_mipo);
2880        A= GF2FalphaRep (A, vBuf);
2881        Variable v= chooseExtension (vBuf, beta, k);
2882        ExtensionInfo info= ExtensionInfo (v, extension);
2883        factors= multiFactorize (A, info);
2884      }
2885    }
2886    else // need factorization over GF (p^k)
2887    {
2888      if (pow ((double) p, (double) 2*extensionDeg) < (1<<16))
2889      // pass to GF(p^2k)
2890      {
2891        setCharacteristic (p, 2*extensionDeg, 'Z');
2892        ExtensionInfo info= ExtensionInfo (k, cGFName, extension);
2893        factors= multiFactorize (GFMapUp (A, extensionDeg), info);
2894        setCharacteristic (p, extensionDeg, cGFName);
2895      }
2896      else // not able to pass to GF (p^2k), pass to F_p (\alpha)
2897      {
2898        setCharacteristic (p);
2899        Variable v1= rootOf (gf_mipo);
2900        A= GF2FalphaRep (A, v1);
2901        Variable v2= chooseExtension (v1, v1, k);
2902        CanonicalForm primElem, imPrimElem;
2903        bool primFail= false;
2904        Variable vBuf;
2905        primElem= primitiveElement (v1, v1, primFail);
2906        if (primFail)
2907          ; //ERROR
2908        else
2909          imPrimElem= mapPrimElem (primElem, v1, v2);
2910        CFList source, dest;
2911        CanonicalForm bufA= mapUp (A, v1, v2, primElem, imPrimElem,
2912                                     source, dest);
2913        ExtensionInfo info= ExtensionInfo (v2, v1, imPrimElem, primElem);
2914        factors= multiFactorize (bufA, info);
2915        setCharacteristic (p, k, cGFName);
2916        for (CFListIterator i= factors; i.hasItem(); i++)
2917          i.getItem()= Falpha2GFRep (i.getItem());
2918      }
2919    }
2920    return factors;
2921  }
2922}
2923
2924#endif
2925/* HAVE_NTL */
2926
Note: See TracBrowser for help on using the repository browser.