source: git/libfac/factor/Factor.cc @ 9e47237

jengelh-datetimespielwiese
Last change on this file since 9e47237 was 9e47237, checked in by Hans Schoenemann <hannes@…>, 11 years ago
chg: Factorize -> factorize, p2
  • Property mode set to 100644
File size: 39.4 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2static const char * errmsg = "\nYou found a bug!\nPlease inform singular@mathematik.uni-kl.de\nPlease include above information and your input (the ideal/polynomial and characteristic) in your bug-report.\nThank you.";
3///////////////////////////////////////////////////////////////////////////////
4// FACTORY - Includes
5#include <factory.h>
6#ifndef NOSTREAMIO
7#ifdef HAVE_IOSTREAM
8#include <iostream>
9#define CERR std::cerr
10#define CIN std::cin
11#elif defined(HAVE_IOSTREAM_H)
12#include <iostream.h>
13#define CERR cerr
14#define CIN cin
15#endif
16#endif
17// Factor - Includes
18#include "tmpl_inst.h"
19#include "SqrFree.h"
20#include "helpstuff.h"
21#include "MVMultiHensel.h"
22#include "Truefactor.h"
23#include "homogfactor.h"
24#include "interrupt.h"
25// some CC's need this:
26#include "Factor.h"
27
28#include "alg_factor.h"
29void out_cf(char *s1,const CanonicalForm &f,char *s2);
30void out_cff(CFFList &L);
31
32
33#ifdef FACTORDEBUG
34#  define DEBUGOUTPUT
35#else
36#  undef DEBUGOUTPUT
37#endif
38
39#include <libfac/factor/debug.h>
40#include "timing.h"
41TIMING_DEFINE_PRINT(factorize_time)
42TIMING_DEFINE_PRINT(sqrfree_time)
43TIMING_DEFINE_PRINT(discr_time)
44TIMING_DEFINE_PRINT(evaluate_time)
45TIMING_DEFINE_PRINT(hensel_time)
46TIMING_DEFINE_PRINT(truefactor_time)
47
48/*
49* a wrapper for factorize over algebraic extensions:
50* does a sanity check and, if nec., a conversion
51* before calling factorize(f,alpha)
52* ( in factorize, alpha.level() must be < 0 )
53*/
54static
55CFFList factorize2 ( const CanonicalForm & f,
56                     const Variable & alpha, const CanonicalForm & mipo )
57{
58  if (alpha.level() <0)
59  {
60    return factorize(f,alpha);
61  }
62  else
63  {
64    bool repl=(f.mvar() != alpha);
65    //out_cf("f2 - factor:",f,"\n");
66    //out_cf("f2 - ext:",alpha,"\n");
67    //out_cf("f2 - mipo:",mipo,"\n");
68    Variable X=rootOf(mipo);
69    CanonicalForm F=f;
70    if (repl) F=replacevar(f,alpha,X);
71    //out_cf("call - factor:",F,"\n");
72    //out_cf("call - ext:",X,"\n");
73    //out_cf("call - mipo:",getMipo(X,'A'),"\n");
74    CFFList L=factorize(F,X);
75    CFFListIterator i=L;
76    if (repl)
77    {
78      CFFList Outputlist;
79      for(;i.hasItem(); i++ )
80      {
81        Outputlist.append(CFFactor(
82        replacevar(i.getItem().factor(),X,alpha),
83        i.getItem().exp()));
84      }
85      return Outputlist;
86    }
87    else return L;
88  }
89}
90///////////////////////////////////////////////////////////////
91// Choose a main variable if the user didn`t wish a          //
92// special one. Returns level of main variable.              //
93///////////////////////////////////////////////////////////////
94static int
95choose_main_variable( const CanonicalForm & f, int Mainvar=0){
96  CanonicalForm remlc, newlc;
97  int n= level(f), mainvar= Mainvar;
98
99  if (mainvar != 0) return mainvar ; // We force use of the wished mainvar
100  remlc= LC(f,n); mainvar = n;
101  if ( totaldegree(remlc)==0 ){ remlc=f.genOne() ; }
102  DEBOUTLN(CERR, "remlc= " , remlc);
103  for ( int i=n-1; i>=1; i-- )
104  {
105    newlc= LC(f,i);
106    if ( totaldegree(newlc)==0 ){ newlc=f.genOne() ; }
107    DEBOUTLN(CERR, "newlc= " , newlc);
108    if ( (remlc.isOne()) && (newlc.isOne()) ){ // take care of the degrees
109      if ( degree(f,i) < degree(f,mainvar) ){
110        remlc= newlc;
111        mainvar= i;
112      }
113    }
114    else  if ( (! remlc.isOne() ) && ( newlc.isOne() ) ){
115      remlc= newlc;
116      mainvar= i;
117    }
118  }
119  return mainvar;
120}
121
122///////////////////////////////////////////////////////////////
123// Check if the derivative is nonzero for oldmainvar.        //
124// Returns the level of the choosen main variable.           //
125///////////////////////////////////////////////////////////////
126static int
127necessary_condition( const CanonicalForm & F, int oldmainvar){
128  CanonicalForm g;
129  int n=level(F);
130
131  g= swapvar(F,oldmainvar,n);
132  g= g.deriv();
133  if ( g.isZero() )
134  {
135    for ( int i=n; i>=1; i-- )
136    {
137      g= swapvar(F,i,n);
138      g= g.deriv();
139      if ( ! g.isZero() ) return i;
140    }
141  }
142  return oldmainvar;
143}
144
145///////////////////////////////////////////////////////////////
146// Make F monic. Return monic polynomial.                    //
147///////////////////////////////////////////////////////////////
148static CanonicalForm
149make_monic( const CanonicalForm & F, const CanonicalForm & lt)
150{
151  CanonicalForm intermediatpoly,f;
152  Variable x(level(F));
153
154  if ( degree(lt) == 0 ) f= 1/lt * F ;
155  else
156  {
157    intermediatpoly= power(lt,degree(F)-1);
158    for ( int i=0; i<=degree(F); i++ )
159      if ( ! F[i].isZero())
160        f+= (F[i] * intermediatpoly*power(x,i))/power(lt,i);
161  }
162  return f;
163}
164
165///////////////////////////////////////////////////////////////
166// Decide whether num/denum (num,denum both from the         //
167// FiniteFielddomain)  lies in the RationalDomain.           //
168// If false, return num/denum else return the zero poly from //
169// the FiniteFielddomain.                                    //
170///////////////////////////////////////////////////////////////
171static CanonicalForm
172is_rational( const CanonicalForm & num, const CanonicalForm & denum ){
173  CanonicalForm a, b;
174  int retvalue;
175
176  retvalue= mydivremt(num,denum,a,b);
177  if ( retvalue && b == num.genZero() ) // num/denum from FFdomain
178    return a;
179  else // num/denum is rational
180    return num.genZero();
181}
182
183///////////////////////////////////////////////////////////////
184// lt_is_product returns 1 iff lt is a product, 0 iff lt is  //
185// a sum.                                                    //
186///////////////////////////////////////////////////////////////
187static int
188lt_is_product( const CanonicalForm & lt ){
189  CFList result;
190
191  result= get_Terms(lt);
192  if ( result.length() > 1 ) return 0;
193  else return 1;
194}
195
196///////////////////////////////////////////////////////////////
197// Reverse the make_monic transformation.                    //
198// Return the list of factors.                               //
199///////////////////////////////////////////////////////////////
200static CFFList
201not_monic( const CFFList & TheList, const CanonicalForm & ltt, const CanonicalForm & F, int levelF)
202{
203  CFFList Returnlist,IntermediateList;
204  CFFListIterator i;
205  CanonicalForm intermediate,lt= ltt,savelc;
206  CanonicalForm numerator,denumerator,test,a,b;
207  Variable x(level(F));
208  int test1;
209
210  if ( lt.isOne() ) return TheList; // the poly was already monic
211  if ( TheList.length() <= 1 ) // only one factor to substitute back
212  {
213    if ( totaldegree(lt) == 0 ) // lt is type numeric
214      Returnlist.append( CFFactor(lt*TheList.getFirst().factor(),
215                                  TheList.getFirst().exp()) );
216    else
217    {
218      intermediate = F(x*lt, levelF)/power(lt,degree(F,levelF)-1);
219      Returnlist.append(CFFactor(intermediate,TheList.getFirst().exp()));
220    }
221  }
222  else // more then one factor
223  {
224    IntermediateList= TheList;
225    if ( totaldegree(lt) == 0 ){ // lt is type numeric;(SqrFree-use, see above)
226      Returnlist.append( CFFactor(lt*IntermediateList.getFirst().factor()
227                                  , IntermediateList.getFirst().exp()) );
228      IntermediateList.removeFirst();
229      Returnlist= Union(Returnlist,IntermediateList);
230    }
231    else // lt is a) a product or b) a sum of terms
232    {
233      if ( lt_is_product(lt) ) // case a)
234      {
235        DEBOUTLN(CERR, "lt_is_product: ", lt);
236        savelc= content(lt) ; // can we simplify to savelc= lc(lt); ?
237        while ( getNumVars(savelc) != 0 )
238          savelc= content(savelc);
239        for ( i=TheList; i.hasItem();i++ )
240        {
241          numerator= i.getItem().factor();
242          numerator= numerator(x*lt,levelF); // x <- x*lt
243          denumerator= power(lt,degree(F,levelF)-1); // == lt^(1-degree(F,x)
244          while (numerator.genZero() == is_rational(numerator, denumerator))
245            numerator*= lt;
246          intermediate= is_rational(numerator,denumerator);
247
248          Returnlist.append( CFFactor(lc(content(intermediate))*intermediate/content(intermediate), i.getItem().exp() ) );
249        }
250        // Now we add a test. If product(factors)/F is a multiple of
251        // savelc, we have to add 1/multiplicity to the factors
252        IntermediateList= Returnlist;
253        intermediate= 1;
254        for ( CFFListIterator j=IntermediateList; j.hasItem(); j++)
255          intermediate*= j.getItem().factor();
256        test1= mydivremt( intermediate,F,a,b);
257        if ( test1 && b == intermediate.genZero() ) // Yupp!
258        {
259          IntermediateList.append(CFFactor(1/a,1));
260          Returnlist= IntermediateList;
261        }
262        else { Returnlist= IntermediateList; }
263      }
264      else // case b)
265      {
266        DEBOUTLN(CERR, "lt_is_sum: ", lt);
267        CanonicalForm save_denumerator= 1;
268        for ( i=TheList; i.hasItem(); i++ )
269        {
270          numerator= i.getItem().factor();
271          numerator= numerator(x*lt,levelF); // x <- x*lt
272          denumerator= power(lt,degree(numerator,levelF)); // == lt^(-degree(numerator,x)
273          test= content(numerator,x);
274          test1= mydivremt(denumerator,test,a,b);
275          if ( test1 && b == numerator.genZero() ) // Yupp!
276          {
277            save_denumerator*= a;
278            Returnlist.append(CFFactor(numerator/test ,1));
279          }
280          else
281          {
282            factoryError("libfac: ERROR: not_monic1: case lt is a sum.");
283          }
284        }
285        // Now we add a test if we did the right thing:
286        // save_denumerator should be a multiple of the leading coeff
287        test1= mydivremt(save_denumerator,lt,a,b);
288        if ( test1 && b == save_denumerator.genZero() ) // Yupp!
289          // We have to multiply one of the factors with
290          // the multiplicity of the save_denumerator <-> lc
291          // the following will do what we want
292          Returnlist= myUnion( CFFList(CFFactor(1/a,1)),Returnlist) ;
293        else
294        {
295          factoryError("libfac: ERROR: not_monic2: case lt is a sum.");
296        }
297      }
298    }
299  }
300  DEBOUTLN(CERR,"Returnlist: ", Returnlist);
301  return Returnlist;
302}
303
304///////////////////////////////////////////////////////////////
305// Substitute the (Variable,Value)-Pair(s) from Substitution-//
306// list into the polynomial F. Returns the resulting poly.   //
307///////////////////////////////////////////////////////////////
308static CanonicalForm
309substitutePoly( const CanonicalForm & F, const SFormList & Substitutionlist){
310  CanonicalForm f= F;
311
312  for ( SFormListIterator i=Substitutionlist; i.hasItem(); i++ )
313    f= f(i.getItem().exp(),level(i.getItem().factor()));
314  return f;
315}
316
317///////////////////////////////////////////////////////////////
318// Find specialization values for the poly F. Returns 0 if   //
319// procedure failed, 1 otherwise. On success Substitutionlist//
320// holds (Variable,Value)-pairs. On failure we only have a   //
321// partitial list.                                           //
322///////////////////////////////////////////////////////////////
323//      *** This is the version with extensions ***          //
324///////////////////////////////////////////////////////////////
325
326///////////////////////////////////////////////////////////////
327// is CF g ok?                                               //
328///////////////////////////////////////////////////////////////
329static int
330various_tests( const CanonicalForm & g, int deg, int vars_left)
331{
332  CFMap m;
333
334  if ( degree(g) == deg ) // degrees match
335    if ( level(compress(g,m)) == (vars_left) ) // exactly one variable less
336      if ( SqrFreeTest(g,1) ) // poly is sqrfree
337        if ( gcd(g,g.deriv()).isOne() ) // Discriminante != 0
338           return 1;
339  return 0;
340}
341
342///////////////////////////////////////////////////////////////
343// specialize one variable over the given field.             //
344///////////////////////////////////////////////////////////////
345// substitutes in poly f of degree deg with former
346// former_nr_of_variables variables the variable nr_of_variable ;
347// this is done in the field of Char getCharacteristic() and
348// Extension given by Extgenerator.
349///////////////////////////////////////////////////////////////
350static int
351specialize_variable( CanonicalForm & f, int deg, SFormList & Substitutionlist, int nr_of_variable,
352                     int former_nr_of_variables, CFGenerator & Extgenerator ){
353  CanonicalForm g;
354  Variable x(nr_of_variable);
355
356  DEBOUTLN(CERR, "specialize_variable: called with: ", f);
357  for ( Extgenerator.reset(); Extgenerator.hasItems(); Extgenerator.next() ){
358    DEBOUTLN(CERR, "  specialize_variable: trying:  ", Extgenerator.item());
359    g= f( Extgenerator.item(), x );
360    DEBOUTLN(CERR, "  specialize_variable: resulting g= ", g);
361    if ( various_tests(g,deg,former_nr_of_variables - nr_of_variable ) ){
362      Substitutionlist.insert(SForm(x,Extgenerator.item())); // append (Var,value) pair
363      f= g;
364      return 1;
365    }
366  }
367  return 0;
368}
369static int
370specialize_agvariable( CanonicalForm & f, int deg, SFormList & Substitutionlist, int nr_of_variable,
371                     int former_nr_of_variables, AlgExtGenerator & Extgenerator ){
372  CanonicalForm g;
373  Variable x(nr_of_variable);
374
375  DEBOUTLN(CERR, "specialize_variable: called with: ", f);
376  for ( Extgenerator.reset(); Extgenerator.hasItems(); Extgenerator.next() ){
377    DEBOUTLN(CERR, "  specialize_variable: trying:  ", Extgenerator.item());
378    g= f( Extgenerator.item(), x );
379    DEBOUTLN(CERR, "  specialize_variable: resulting g= ", g);
380    if ( various_tests(g,deg,former_nr_of_variables - nr_of_variable ) ){
381      Substitutionlist.insert(SForm(x,Extgenerator.item())); // append (Var,value) pair
382      f= g;
383      return 1;
384    }
385  }
386  return 0;
387}
388
389///////////////////////////////////////////////////////////////
390// generate a minpoly of degree degree_of_Extension in the   //
391// field getCharacteristik()^Extension.                      //
392///////////////////////////////////////////////////////////////
393CanonicalForm
394generate_mipo( int degree_of_Extension , const Variable & Extension ){
395  FFRandom gen;
396  if ( degree(Extension) > 0 ) GFRandom gen;
397  else {
398    if ( degree(Extension) == 0 ) FFRandom gen;
399    else
400    {
401      factoryError("libfac: evaluate: Extension not inFF() or inGF() !");
402    }
403  }
404  return find_irreducible( degree_of_Extension, gen, Variable(1) );
405}
406
407///////////////////////////////////////////////////////////////
408// Try to find a specialization for f over the field of char //
409// f.getCharacteristic() and (possible) extension defined by //
410// the variable Extension .                                  //
411// Returns 1 iff specialisation was found, 0 otherwise.      //
412// If 0 is returned there are variables left to substitute.  //
413// We check if Substitutionlist.length() > 0, i.e. we        //
414// previously tried to find specialization values for some   //
415// values. We take them and work with the resulting poly.    //
416///////////////////////////////////////////////////////////////
417static int
418try_specializePoly(const CanonicalForm & f, const Variable & Extension, int deg, SFormList & Substitutionlist, int ii,int j)
419{
420  int ok,i= ii;
421  CanonicalForm ff= f;
422
423  if ( Substitutionlist.length() > 0 ){ // we formerly tried to specialize
424    ff= substitutePoly(f,Substitutionlist); // substitute found values
425    i= Substitutionlist.length() + 1;
426  }
427
428  if ( degree(Extension) > 0 )
429  { // working over Extensions
430    DEBOUTLN(CERR, "try_specializePoly: working over Extensions: ", Extension);
431    if (Extension.level() > 0)
432    {
433    //  AlgExtGenerator g(Extension,minpoly );
434    //  for ( int k=i ; k<j ; k++ ) // try to find specialization for all
435    //  {                           // variables (# = k ) beginning with the
436    //                             // starting value i
437    //    ok= specialize_agvariable( ff, deg, Substitutionlist, k, j, g );
438    //    if ( ! ok ) return 0; // we failed
439    //  }
440      #ifndef NDEBUG
441        //printf("libfac: try_specializePoly: extension level >0\n");
442      #endif
443      return 0; // we failed
444    }
445    else
446    {
447      AlgExtGenerator g(Extension);
448      for ( int k=i ; k<j ; k++ ) // try to find specialization for all
449      {                           // variables (# = k ) beginning with the
450                                 // starting value i
451        ok= specialize_agvariable( ff, deg, Substitutionlist, k, j, g );
452        if ( ! ok ) return 0; // we failed
453      }
454    }
455  }
456  else{ // working over the ground-field
457    FFGenerator g;
458    DEBOUTMSG(CERR, "try_specializePoly: working over the ground-field.");
459    for ( int k=i ; k<j ; k++ ){
460      ok= specialize_variable( ff, deg, Substitutionlist, k, j, g );
461      if ( ! ok ) return 0; // we failed
462    }
463  }
464  return 1;
465}
466
467static int
468specializePoly(const CanonicalForm & f, Variable & Extension, int deg, SFormList & Substitutionlist, int i,int j){
469  Variable minpoly= Extension;
470  int ok,extended= degree(Extension), working_over_extension;
471
472  // Remember if we are working over an extension-field
473  if ( extended >= 2 )    { working_over_extension = 1; }
474  else                    { working_over_extension = 0; extended = 1; }
475  // First try:
476  ok = try_specializePoly(f,minpoly,deg,Substitutionlist,i,j);
477  while ( ! ok ){ // we have to extend!
478    extended+= 1;
479    if ( ! working_over_extension ){
480      minpoly= rootOf(generate_mipo( extended,Extension ));
481      Extension= minpoly;
482      ok= try_specializePoly(f,minpoly,deg,Substitutionlist,i,j);
483    }
484    else
485    {
486      factoryError("libfac: spezializePoly ERROR: Working over given extension-field not yet implemented!");
487      return 0;
488    }
489  }
490  return 1;
491}
492
493
494// This is a procedure to play with: lot's of parameters!
495// returns: 0  iff no success (possibly because Extension isn't great enough
496//          >0 iff g (univariate) splits into n factors;
497// if n>0 BestEvaluationpoint contains the choice of values for the variables
498//
499// tries to find at least maxtries evaluation points
500// if g factored sametries into the same number of poly's the procedure stops
501// if we tried failtries evaluations not found valid, we stop. Perhaps
502// Extension isn't big enough!
503static int
504evaluate( int maxtries, int sametries, int failtries, const CanonicalForm &f , const Variable & Extension, const CanonicalForm &mipo, SFormList & BestEvaluationpoint, CFFList & BestFactorisation ){
505  int minfactors=degree(f),degf=degree(f),n=level(f.mvar())-1;
506  SFormList minEvaluation;
507  CFFList minFactorisation;
508  int samefactors=0, failedfactor=0, tried=0;
509  FFRandom gen;
510  CFFList unilist;
511
512  if ( degree(Extension) >0 ) GFRandom gen;
513  else
514  {
515    if ( degree(Extension) == 0 ) FFRandom gen;
516    else
517    {
518      factoryError("libfac: evaluate: Extension not inFF() or inGF() !");
519    }
520  }
521  REvaluation k(1,n,gen);
522  k.nextpoint();
523  for ( int i=1; i<=maxtries ; i++)
524  {
525    // k.nextpoint();
526    SFormList Substitutionlist;
527    for ( int j=1; j<=n; j++ )
528     Substitutionlist.insert(SForm(Variable(j),k[j]));
529    k.nextpoint();
530    CanonicalForm g=substitutePoly(f,Substitutionlist);
531    if ( various_tests(g, degf,1) )
532    { // found a valid point
533      failedfactor = 0; tried += 1;
534      if ( degree(Extension) == 0   )
535        unilist = factorize(g,1); // poly is sqr-free!
536      else
537      {
538        unilist = factorize2(g,Extension,mipo);
539      }
540      if (unilist.length() <= minfactors )
541      {
542        minfactors=unilist.length();
543        minEvaluation=Substitutionlist;
544        minFactorisation=unilist;
545      }
546      else samefactors +=1;
547
548      if (unilist.length() == 1 ) // wow! we found f is irreducible!
549      {
550        BestEvaluationpoint=minEvaluation;
551        BestFactorisation=minFactorisation;
552        return 1;
553      }
554
555      if ( samefactors >= sametries ) // now we stop ( maybe polynomial *has*
556                                      // minfactors factors? )
557      {
558        BestEvaluationpoint=minEvaluation;
559        BestFactorisation=minFactorisation;
560        return minfactors;
561      }
562
563    }
564    else
565      failedfactor += 1;
566
567    if ( failedfactor >= failtries ) // now we stop ( perhaps Extension isn't
568                                     // big enough )
569    {
570      if ( tried == 0 )
571        return 0;
572      else
573      {
574        BestEvaluationpoint=minEvaluation;
575        BestFactorisation=minFactorisation;
576        return minfactors;
577      }
578    }
579  }
580  BestEvaluationpoint=minEvaluation;
581  BestFactorisation=minFactorisation;
582  return minfactors;
583}
584
585///////////////////////////////////////////////////////////////
586// A factorization routine for a sqrfree polynomial.         //
587// Returns the list of factors.                              //
588///////////////////////////////////////////////////////////////
589CFFList
590Factorized( const CanonicalForm & F, const CanonicalForm & alpha, int Mainvar)
591{
592  CanonicalForm f,lt,ff,ffuni;
593  Variable Extension=alpha.mvar();
594  CFFList Outputlist,UnivariateFactorlist,Outputlist2;
595  SFormList Substitutionlist, Evaluationpoint;
596  CFFactor copy;
597  int mainvar=Mainvar,success,oldmainvar;
598  CFMap m;
599
600  // INTERRUPTHANDLER
601  if ( interrupt_handle() ) return CFFList() ;
602  // INTERRUPTHANDLER
603
604  if (F.inCoeffDomain()) {  return CFFList(CFFactor(F,1)); }
605  if ( F.isUnivariate() ) // could have lost one Variable elsewhere
606  {
607    if ( degree(Extension) == 0 )
608    {
609      TIMING_START(evaluate_time);
610      Outputlist = factorize(F,1); // poly is sqr-free
611      TIMING_END(evaluate_time);
612      return Outputlist;
613    }
614    else
615    {
616      if (Extension.level()<0)
617      DEBOUTLN(CERR, "Univ. Factorization over extension of degree ",
618               degree(getMipo(Extension,'x')) );
619      else
620      DEBOUTLN(CERR, "Univ. Factorization over extension of level ??",
621                Extension.level());
622      TIMING_START(evaluate_time);
623      Outputlist = factorize2(F,Extension,alpha);
624      TIMING_END(evaluate_time);
625      return Outputlist;
626    }
627  }
628
629  if ( Mainvar ) oldmainvar=Mainvar; else oldmainvar=level(F);
630  // First choose a main variable; this may be revisted in the next step
631  mainvar = choose_main_variable(F);
632  // Let`s look if @f/@mainvar is nonzero
633  mainvar = necessary_condition(F,mainvar);
634  // Now we have definetly choosen a main variable
635  // swap poly such that the mainvar has highest level
636  f=swapvar(F,mainvar,level(F));
637
638  // INTERRUPTHANDLER
639  if ( interrupt_handle() ) return CFFList() ;
640  // INTERRUPTHANDLER
641
642  if ( oldmainvar != mainvar ){
643    DEBOUTSL(CERR); DEBOUT(CERR,"Swapped poly ", F);
644    DEBOUT(CERR, " in ", f); DEBOUTNL(CERR);
645    DEBOUTSL(CERR); DEBOUT(CERR,"Swapped  ", oldmainvar );
646    DEBOUT(CERR, " <-- ", mainvar ); DEBOUT(CERR, "  Mainvar= ", f.mvar());
647    DEBOUTNL(CERR);
648    ff = f.deriv();
649    TIMING_START(discr_time);
650    ffuni = gcd(f,ff);
651    TIMING_END(discr_time);
652    if ( !(ffuni.isOne()) ){ //discriminante nonzero: split poly
653      DEBOUTLN(CERR,"Nontrivial GCD of f= ", f);
654      DEBOUTLN(CERR,"             and @f= ", ff);
655      DEBOUTLN(CERR,"          GCD(f,@f)= ", ffuni);
656      ff=f/ffuni;
657      CFFList Outputlist_a, Outputlist_b;
658      Outputlist_a = Factorized(ff,alpha);
659      DEBOUTLN(CERR, "Outputlist_a = ", Outputlist_a);
660      Outputlist_b = Factorized(ffuni,alpha);
661      DEBOUTLN(CERR, "Outputlist_b = ", Outputlist_b);
662      Outputlist = myUnion(Outputlist_a, Outputlist_b);
663      // have to back-swapvar the factors....
664      for ( CFFListIterator i=Outputlist; i.hasItem(); i++ ){
665        copy=i.getItem();
666        Outputlist2.append(CFFactor(swapvar(copy.factor(),oldmainvar,mainvar),copy.exp()));
667      }
668      DEBOUTLN(CERR, "Outputlist2 (a+b swapped) (to return) = ", Outputlist2);
669      return Outputlist2;
670    }
671  }
672
673  // Check special cases
674  for ( int i=1; i<=level(F); i++)
675  {
676    if ( degree(f,Variable(i) ) == 1 )
677    //test trivial case; only true iff F is primitiv w.r.t every variable; else check (if F=ax+b) gcd(a,b)=1 ?
678    {
679      DEBOUTLN(CERR, "Trivial case: ", F);
680      Outputlist.append(CFFactor(F,1));
681      return Outputlist;
682    }
683  }
684
685  // Look at the leading term:
686  lt = LC(f);
687  DEBOUTLN(CERR, "Leading term: ", lt);
688  //if ( lt != f.genOne() )
689  if ( !lt.isOne() )
690  {
691    // make the polynomial monic in the main variable
692    ff = make_monic(f,lt); ffuni = ff;
693    DEBOUTLN(CERR, "make_monic returned: ", ff);
694  }
695  else{ ff= f; ffuni= ff; }
696
697  TIMING_START(evaluate_time);
698  success=evaluate(min(10,max(degree(ff), 5)), min(degree(ff),3), min(degree(ff),3), ff, Extension, alpha, Substitutionlist,UnivariateFactorlist);
699  DEBOUTLN(CERR,  "Returned from evaluate: success: ", success);
700  for ( SFormListIterator ii=Substitutionlist; ii.hasItem(); ii++ )
701  {
702    DEBOUTLN(CERR, "Substituting ", ii.getItem().factor());
703    DEBOUTLN(CERR, "       with value: ", ii.getItem().exp());
704  }
705
706  if ( success==0 ) // evalute wasn't successfull
707  {
708    success= specializePoly(ffuni,Extension,degree(ff),Substitutionlist,1,getNumVars(compress(ff,m)));
709    DEBOUTLN(CERR,  "Returned from specializePoly: success: ", success);
710    if (success == 0 ) // No spezialisation could be found
711    {
712      factoryError("libfac: Factorize: ERROR: Not able to find a valid specialization!");
713      Outputlist.append(CFFactor(F,1));
714      return Outputlist;
715    }
716
717    // INTERRUPTHANDLER
718    if ( interrupt_handle() ) return CFFList() ;
719    // INTERRUPTHANDLER
720
721    ffuni = substitutePoly(ff,Substitutionlist);
722    // We now have an univariat poly; factorize that
723    if ( degree(Extension) == 0   )
724    {
725      DEBOUTMSG(CERR, "Univ. Factorization over the ground field");
726      UnivariateFactorlist = factorize(ffuni,1); // univ. poly is sqr-free!
727    }
728    else
729    {
730      DEBOUTLN(CERR, "Univ. Factorization over extension of degree ",
731               degree(getMipo(Extension,'x')) );
732      UnivariateFactorlist = factorize2(ffuni,Extension,alpha);
733    }
734  }
735  else
736  {
737    ffuni = substitutePoly(ff,Substitutionlist);
738  }
739    TIMING_END(evaluate_time);
740  if (UnivariateFactorlist.length() == 1)
741  { // poly is irreduzibel
742    DEBOUTLN(CERR, "Univ. poly is irreduzible: ", UnivariateFactorlist);
743    Outputlist.append(CFFactor(F,1));
744    return Outputlist;
745  }
746  else
747  { // we have factors
748    DEBOUTSL(CERR);
749    DEBOUT(CERR, "Univariate poly has " , UnivariateFactorlist.length());
750    DEBOUT(CERR, " factors:  ", ffuni);
751    DEBOUT(CERR, " = ", UnivariateFactorlist); DEBOUTNL(CERR);
752
753    // INTERRUPTHANDLER
754    if ( interrupt_handle() ) return CFFList() ;
755    // INTERRUPTHANDLER
756
757    TIMING_START(hensel_time);
758    Outputlist = MultiHensel(ff,UnivariateFactorlist,Substitutionlist, alpha);
759    DEBOUTLN(CERR, "Outputlist after MultiHensel: ", Outputlist);
760    TIMING_END(hensel_time);
761
762    // INTERRUPTHANDLER
763    if ( interrupt_handle() ) return CFFList() ;
764    // INTERRUPTHANDLER
765
766    TIMING_START(truefactor_time);
767    Outputlist = Truefactors(ff, level(ff), Substitutionlist, Outputlist);
768    DEBOUTLN(CERR, "Outputlist after Truefactors: ", Outputlist);
769    TIMING_END(truefactor_time);
770
771    // INTERRUPTHANDLER
772    if ( interrupt_handle() ) return CFFList() ;
773    // INTERRUPTHANDLER
774
775    //if ( lt != f.genOne() )
776    if ( !lt.isOne() )
777    {
778      Outputlist = not_monic(Outputlist,lt,ff,level(ff));
779      DEBOUTLN(CERR, "not_monic returned: ", Outputlist);
780    }
781
782    // have to back-swapvar the factors....
783    for ( CFFListIterator i=Outputlist; i.hasItem(); i++ )
784    {
785      copy=i.getItem();
786      Outputlist2.append(CFFactor(swapvar(copy.factor(),oldmainvar,mainvar),copy.exp()));
787    }
788
789    return Outputlist2;
790  }
791}
792
793int cmpCF( const CFFactor & f, const CFFactor & g );
794
795///////////////////////////////////////////////////////////////
796// The user front-end for a uni/multivariate factorization   //
797// routine. F needs not to be SqrFree.                       //
798// Option of * choosing a  main variable (n.y.i.)            //
799//           * choosing an algebraic extension (n.y.u.)      //
800//           * ensuring poly is sqrfree (n.y.i.)             //
801// use Factorize(F,alpha,is_SqrFree) if not over Zp[x]/Q[x]  //
802///////////////////////////////////////////////////////////////
803int find_mvar(const CanonicalForm &f);
804CFFList Factorize(const CanonicalForm & F, int is_SqrFree )
805{
806  //out_cf("Factorize ",F,"\n");
807  CFFList Outputlist;
808
809  // INTERRUPTHANDLER
810  if ( interrupt_handle() ) return CFFList() ;
811  // INTERRUPTHANDLER
812
813  DEBINCLEVEL(CERR, "Factorize");
814  DEBOUTLN(CERR, "Called with F= ", F);
815  if (( getCharacteristic() == 0 ) || (F.isUnivariate()))
816  { // char == 0
817    TIMING_START(factorize_time);
818    //CERR << "Factoring in char=0 of " << F << " = " << Outputlist << "\n";
819    Outputlist= factorize(F);
820    // Factorization in char=0 doesn't sometimes return at least two elements!!!
821    if ( getNumVars(Outputlist.getFirst().factor()) != 0 )
822      Outputlist.insert(CFFactor(1,1));
823    //CERR << "  Factorize in char=0: returning with: " << Outputlist << "\n";
824    TIMING_END(factorize_time);
825    DEBDECLEVEL(CERR, "Factorize");
826    TIMING_PRINT(factorize_time, "\ntime used for factorization   : ");
827    return Outputlist;
828  }
829  CFFList SqrFreeList,Intermediatelist,Outputlist2;
830  ListIterator<CFFactor> i,j;
831  CanonicalForm g=1,unit=1,r=1;
832  Variable minpoly; // dummy
833  int exp;
834  CFMap m;
835  TIMING_START(factorize_time);
836  // search an "optimal" main variavble
837  int mv=F.level();
838  if ((mv != LEVELBASE) /* && (! F.isUnivariate()) */)
839  {
840     mv=find_mvar(F);
841     if (mv!=F.level())
842     {
843       swapvar(F,Variable(mv),F.mvar());
844     }
845  }
846
847  ///////
848  // Maybe it`s better to add a sqrfree-test before?
849  // (If gcd is fast...)
850  ///////
851  //  if ( ! SqrFreeTest(F) ){
852  if ( ! is_SqrFree )
853  {
854    TIMING_START(sqrfree_time);
855    SqrFreeList = SqrFreeMV(F) ; // first sqrfree the polynomial
856    // don't use sqrFree(F), factory's internal sqrFree for multiv.
857    // Polynomials; it's wrong!! Ex.: char=p   f= x^p*(y+1);
858    // SqrFreeMV(f)= ( y+1, (x)^p ), sqrFree(f)= ( y+1 ) .
859    TIMING_END(sqrfree_time);
860
861    // INTERRUPTHANDLER
862    if ( interrupt_handle() ) return CFFList() ;
863    // INTERRUPTHANDLER
864
865  }
866  else
867    SqrFreeList.append(CFFactor(F,1));
868
869  DEBOUTLN(CERR, "SqrFreeMV= ", SqrFreeList);
870  for ( i=SqrFreeList; i.hasItem(); i++ )
871  {
872    DEBOUTLN(CERR, "Factor under consideration: ", i.getItem().factor());
873    // We need a compress on each list item ! Maybe we have less variables!
874    g =compress(i.getItem().factor(),m);
875    exp = i.getItem().exp();
876    if ( getNumVars(g) ==0 ) // a constant; Exp==1
877      Outputlist.append( CFFactor(g,1) ) ;
878    else// a real polynomial
879      if ( g.isUnivariate() )
880      {
881        //out_cf("univ. poly: ",g,"\n");
882        Intermediatelist=factorize(g,1); // poly is sqr-free!
883        for ( j=Intermediatelist; j.hasItem(); j++ )
884          //Normally j.getItem().exp() should be 1
885          Outputlist.append( CFFactor( m(j.getItem().factor()),exp*j.getItem().exp()));
886      }
887      else
888      { // multivariate polynomial
889        if ( g.isHomogeneous() )
890        {
891          DEBOUTLN(CERR, "Poly is homogeneous! : ", g);
892          // Now we can substitute one variable to 1, factorize and then
893          // look on the resulting factors and their monomials for
894          // backsubstitution of the substituted variable.
895          Intermediatelist = HomogFactor(g, minpoly, 0);
896        }
897        else // not homogeneous
898          Intermediatelist = Factorized(g, minpoly, 0);
899
900        // INTERRUPTHANDLER
901        if ( interrupt_handle() ) return CFFList() ;
902        // INTERRUPTHANDLER
903
904        for ( j=Intermediatelist; j.hasItem(); j++ )
905          //Normally j.getItem().exp() should be 1
906          Outputlist= myappend( Outputlist, CFFactor(m(j.getItem().factor()),exp*j.getItem().exp()));
907      }
908  }
909  g=1; unit=1;
910  DEBOUTLN(CERR, "Outputlist is ", Outputlist);
911  for ( i=Outputlist; i.hasItem(); i++ )
912    if ( level(i.getItem().factor()) > 0 )
913    {
914      unit = lc(i.getItem().factor());
915      if ( getNumVars(unit) == 0 )
916      { // a constant; possibly 1
917        Outputlist2.append(CFFactor(i.getItem().factor()/unit , i.getItem().exp()));
918        g *=power(i.getItem().factor()/unit,i.getItem().exp());
919      }
920      else
921      {
922        Outputlist2.append(i.getItem());
923        g *=power(i.getItem().factor(),i.getItem().exp());
924      }
925    }
926
927  r=F/g;
928  Outputlist2.insert(CFFactor(r,1));
929
930  if ((mv!=F.level()) && (! F.isUnivariate() ))
931  {
932    CFFListIterator J=Outputlist2;
933    for ( ; J.hasItem(); J++)
934    {
935      swapvar(J.getItem().factor(),Variable(mv),F.mvar());
936    }
937    swapvar(F,Variable(mv),F.mvar());
938  }
939  DEBDECLEVEL(CERR, "Factorize");
940  TIMING_END(factorize_time);
941
942  TIMING_PRINT(sqrfree_time, "\ntime used for sqrfree   : ");
943  TIMING_PRINT(discr_time, "time used for discriminante   : ");
944  TIMING_PRINT(evaluate_time, "time used for evaluation and univ. factorization  : ");
945  TIMING_PRINT(hensel_time, "time used for hensel-lift   : ");
946  TIMING_PRINT(truefactor_time, "time used for truefactors   : ");
947  TIMING_PRINT(factorize_time, "\ntime used for factorization   : ");
948
949  if(isOn(SW_USE_NTL_SORT)) Outputlist2.sort(cmpCF);
950
951  return Outputlist2;
952}
953
954///////////////////////////////////////////////////////////////
955// The user front-end for a uni/multivariate factorization   //
956// routine. F needs not to be SqrFree.                       //
957// Option of * choosing a  main variable (n.y.i.)            //
958//           * choosing an algebraic extension (n.y.u.)      //
959//           * ensuring poly is sqrfree (n.y.i.)             //
960///////////////////////////////////////////////////////////////
961static bool fdivides2(const CanonicalForm &F, const CanonicalForm &G, const CanonicalForm &minpoly)
962{
963  if (!minpoly.isZero())
964  {
965  #if 0
966    Variable Alpha=minpoly.mvar();
967    Variable X=rootOf(minpoly);
968    CanonicalForm rF=replacevar(F,Alpha,X);
969    CanonicalForm rG=replacevar(G,Alpha,X);
970    return fdivides(rF,rG);;
971  #else
972    if (degree(F,F.mvar()) > degree(G,F.mvar())) return false;
973    return true;
974    //CanonicalForm a,b;
975    //mydivrem(G,F,a,b);
976    //if (b.isZero()) return true;
977    //else return false;
978  #endif
979  }
980  else
981   return fdivides(F,G);
982}
983
984CFFList
985Factorize(const CanonicalForm & F, const CanonicalForm & minpoly, int is_SqrFree )
986{
987  //out_cf("Factorize: F=",F,"\n");
988  //out_cf("           minpoly:",minpoly,"\n");
989  CFFList Outputlist,SqrFreeList,Intermediatelist,Outputlist2;
990  ListIterator<CFFactor> i,j;
991  CanonicalForm g=1,unit=1,r=1;
992  //Variable minpoly; // reserved (-> Factorisation over algebraic Extensions)
993  int exp;
994  CFMap m;
995
996  // INTERRUPTHANDLER
997  if ( interrupt_handle() ) return CFFList() ;
998  // INTERRUPTHANDLER
999
1000  DEBINCLEVEL(CERR, "Factorize");
1001  DEBOUTLN(CERR, "Called with F= ", F);
1002  if ( getCharacteristic() == 0 )
1003  { // char == 0
1004    TIMING_START(factorize_time);
1005    //CERR << "Factoring in char=0 of " << F << " = " << Outputlist << "\n";
1006    #if 0
1007    // SHOULD: Outputlist= factorize(F,minpoly);
1008    Outputlist= factorize(F);
1009    #else
1010    if (!minpoly.isZero())
1011    {
1012      if ( F.isHomogeneous() )
1013      {
1014        DEBOUTLN(CERR, "Poly is homogeneous! : ", F);
1015        // Now we can substitute one variable to 1, factorize and then
1016        // look on the resulting factors and their monomials for
1017        // backsubstitution of the substituted variable.
1018        Outputlist=HomogFactor(F, minpoly, 0);
1019      }
1020      else
1021      {
1022        CFList as(minpoly);
1023        //CFFList sqF=sqrFree(F); // sqrFreeZ
1024        CFFList sqF=SqrFreeMV(F,minpoly);
1025        if (sqF.isEmpty()) sqF=sqrFree(F);
1026        CFFList G,H;
1027        CanonicalForm fac;
1028        int d;
1029        ListIterator<CFFactor> i,k;
1030        for ( i = sqF; i.hasItem(); ++i )
1031        {
1032          d = i.getItem().exp();
1033          fac = i.getItem().factor();
1034          int success=1;
1035          G = newfactoras( fac, as, success);
1036          for ( k = G; k.hasItem(); ++k )
1037          {
1038            fac = k.getItem().factor();
1039            int dd = k.getItem().exp();
1040            H.append( CFFactor( fac , d*dd ) );
1041          }
1042        }
1043        Outputlist = H;
1044      }
1045    }
1046    else // minpoly==0
1047      Outputlist=factorize(F);
1048    #endif
1049    // Factorization in char=0 doesn't sometimes return at least two elements!!!
1050    if ( getNumVars(Outputlist.getFirst().factor()) != 0 )
1051      Outputlist.insert(CFFactor(1,1));
1052    //CERR << "  Factorize in char=0: returning with: " << Outputlist << "\n";
1053    TIMING_END(factorize_time);
1054    DEBDECLEVEL(CERR, "Factorize");
1055    TIMING_PRINT(factorize_time, "\ntime used for factorization   : ");
1056    //out_cff(Outputlist);
1057    return Outputlist;
1058  }
1059  TIMING_START(factorize_time);
1060  // search an "optimal" main variavble
1061  int mv=F.level();
1062  if (mv != LEVELBASE && ! F.isUnivariate() )
1063  {
1064     mv=find_mvar(F);
1065     if (mv!=F.level())
1066     {
1067       swapvar(F,Variable(mv),F.mvar());
1068     }
1069  }
1070
1071  ///////
1072  // Maybe it`s better to add a sqrfree-test before?
1073  // (If gcd is fast...)
1074  ///////
1075  //  if ( ! SqrFreeTest(F) ){
1076  if ( ! is_SqrFree )
1077  {
1078    TIMING_START(sqrfree_time);
1079    SqrFreeList = SqrFreeMV(F, minpoly) ; // first sqrfree the polynomial
1080    // don't use sqrFree(F), factory's internal sqrFree for multiv.
1081    // Polynomials; it's wrong!! Ex.: char=p   f= x^p*(y+1);
1082    // SqrFreeMV(f)= ( y+1, (x)^p ), sqrFree(f)= ( y+1 ) .
1083    TIMING_END(sqrfree_time);
1084
1085    // INTERRUPTHANDLER
1086    if ( interrupt_handle() ) return CFFList() ;
1087    // INTERRUPTHANDLER
1088
1089  }
1090  else
1091    SqrFreeList.append(CFFactor(F,1));
1092  DEBOUTLN(CERR, "SqrFreeMV= ", SqrFreeList);
1093  for ( i=SqrFreeList; i.hasItem(); i++ )
1094  {
1095    DEBOUTLN(CERR, "Factor under consideration: ", i.getItem().factor());
1096    // We need a compress on each list item ! Maybe we have less variables!
1097    g =compress(i.getItem().factor(),m);
1098    exp = i.getItem().exp();
1099    if ( getNumVars(g) ==0 ) // a constant; Exp==1
1100      Outputlist.append( CFFactor(g,1) ) ;
1101    else// a real polynomial
1102    {
1103      if ( g.isUnivariate() )
1104      {
1105        Variable alpha=rootOf(minpoly);
1106        Intermediatelist=factorize2(g,alpha,minpoly); // poly is sqr-free!
1107        for ( j=Intermediatelist; j.hasItem(); j++ )
1108          //Normally j.getItem().exp() should be 1
1109          Outputlist.append(
1110           CFFactor( m(replacevar(j.getItem().factor(),alpha,minpoly.mvar())),
1111             exp*j.getItem().exp()));
1112      }
1113      else // multivariate polynomial
1114      {
1115        if ( g.isHomogeneous() )
1116        {
1117          DEBOUTLN(CERR, "Poly is homogeneous! : ", g);
1118          // Now we can substitute one variable to 1, factorize and then
1119          // look on the resulting factors and their monomials for
1120          // backsubstitution of the substituted variable.
1121          Intermediatelist = HomogFactor(g, minpoly, 0);
1122        }
1123        else // not homogeneous
1124          Intermediatelist = Factorized(g, minpoly, 0);
1125
1126        // INTERRUPTHANDLER
1127        if ( interrupt_handle() ) return CFFList() ;
1128        // INTERRUPTHANDLER
1129
1130        for ( j=Intermediatelist; j.hasItem(); j++ )
1131          //Normally j.getItem().exp() should be 1
1132          Outputlist= myappend( Outputlist, CFFactor(m(j.getItem().factor()),exp*j.getItem().exp()));
1133      }
1134    }
1135  }
1136  g=1; unit=1;
1137  DEBOUTLN(CERR, "Outputlist is ", Outputlist);
1138  for ( i=Outputlist; i.hasItem(); i++ )
1139    if ( level(i.getItem().factor()) > 0 )
1140    {
1141      unit = lc(i.getItem().factor());
1142      if ( getNumVars(unit) == 0 ){ // a constant; possibly 1
1143        Outputlist2.append(CFFactor(i.getItem().factor()/unit , i.getItem().exp()));
1144        g *=power(i.getItem().factor()/unit,i.getItem().exp());
1145      }
1146      else
1147      {
1148        Outputlist2.append(i.getItem());
1149        g *=power(i.getItem().factor(),i.getItem().exp());
1150      }
1151    }
1152
1153  r=F/g;
1154  Outputlist2.insert(CFFactor(r,1));
1155
1156  if ((mv!=F.level()) && (! F.isUnivariate() ))
1157  {
1158    CFFListIterator J=Outputlist2;
1159    for ( ; J.hasItem(); J++)
1160    {
1161      swapvar(J.getItem().factor(),Variable(mv),F.mvar());
1162    }
1163    swapvar(F,Variable(mv),F.mvar());
1164  }
1165
1166  DEBDECLEVEL(CERR, "Factorize");
1167  TIMING_END(factorize_time);
1168
1169  TIMING_PRINT(sqrfree_time, "\ntime used for sqrfree   : ");
1170  TIMING_PRINT(discr_time, "time used for discriminante   : ");
1171  TIMING_PRINT(evaluate_time, "time used for evaluation and univ. factorization  : ");
1172  TIMING_PRINT(hensel_time, "time used for hensel-lift   : ");
1173  TIMING_PRINT(truefactor_time, "time used for truefactors   : ");
1174  TIMING_PRINT(factorize_time, "\ntime used for factorization   : ");
1175
1176  if(isOn(SW_USE_NTL_SORT)) Outputlist2.sort(cmpCF);
1177
1178  //out_cff(Outputlist2);
1179  return Outputlist2;
1180}
1181
Note: See TracBrowser for help on using the repository browser.