source: git/factory/facFqFactorize.cc @ 8336c9

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