Changeset e7676a in git


Ignore:
Timestamp:
May 7, 2012, 3:55:50 PM (12 years ago)
Author:
Oleksandr Motsak <motsak@…>
Branches:
(u'spielwiese', 'fe61d9c35bf7c61f2b6cbf1b56e25e2f08d536cc')
Children:
517530b37f04ee705b7b271243a265748c447cf5dccd6db99cc44c93669e843ddb6e06d2682769b8
Parents:
a034968a1bff5f6e4e9ad126551a2e9a377d9f6060cc1289a79586c1732ba3885997c3cb49bc01d9
Message:
Merge pull request #100 from mmklee/ezgcd_sw

Ezgcd sw
Files:
42 added
8 edited

Legend:

Unmodified
Added
Removed
  • Tst/Short/ok_s.lst

    ra03496 re7676a  
    132132factorizep_s
    133133factorizeQa_s
     134fermat_gcd_1var
     135fermat_gcd_2var
     136fermat_gcd_3var
     137fermat_gcd_4var
     138fermat_gcd_mod_1var
     139fermat_gcd_mod_2var
     140fermat_gcd_mod_3var
     141fermat_gcd_mod_4var
    134142fetch_s
    135143fglm1_s
     
    141149gaussm_ex
    142150gcd0_s
     151gcd2test
     152gcd3primtest
     153gcd3test
     154gcd4test
     155gcd5primtest
     156gcd5test
    143157gcdp_s
    144158gerhard_1_32003_lp
  • factory/algext.cc

    ra03496 re7676a  
    1 #include <factory/factoryconf.h>
     1#include "config.h"
    22
    33#ifndef NOSTREAMIO
     
    2424#include "cf_map.h"
    2525#include "cf_generator.h"
     26
     27#ifdef HAVE_NTL
     28#include "NTLconvert.h"
     29#endif
    2630
    2731/// compressing two polynomials F and G, M is used for compressing,
     
    585589}
    586590
     591#ifdef HAVE_NTL
     592static CanonicalForm
     593myicontent ( const CanonicalForm & f, const CanonicalForm & c )
     594{
     595    if (f.isOne() || c.isOne())
     596      return 1;
     597    if ( f.inBaseDomain() && c.inBaseDomain())
     598    {
     599      if (c.isZero()) return abs(f);
     600      return bgcd( f, c );
     601    }
     602    else if ( (f.inCoeffDomain() && c.inCoeffDomain()) ||
     603              (f.inCoeffDomain() && c.inBaseDomain()) ||
     604              (f.inBaseDomain() && c.inCoeffDomain()))
     605    {
     606      if (c.isZero()) return abs (f);
     607      ZZX NTLf= convertFacCF2NTLZZX (f);
     608      ZZX NTLc= convertFacCF2NTLZZX (c);
     609      NTLc= GCD (NTLc, NTLf);
     610      if (f.inCoeffDomain())
     611        return convertNTLZZX2CF(NTLc,f.mvar());
     612      else
     613        return convertNTLZZX2CF(NTLc,c.mvar());
     614    }
     615    else
     616    {
     617        CanonicalForm g = c;
     618        for ( CFIterator i = f; i.hasTerms() && ! g.isOne(); i++ )
     619            g = myicontent( i.coeff(), g );
     620        return g;
     621    }
     622}
     623#endif
     624
     625CanonicalForm
     626myicontent ( const CanonicalForm & f )
     627{
     628#ifdef HAVE_NTL
     629    return myicontent( f, 0 );
     630#else
     631    return 1;
     632#endif
     633}
     634
    587635CanonicalForm QGCD( const CanonicalForm & F, const CanonicalForm & G )
    588636{ // f,g in Q(a)[x1,...,xn]
     
    612660  f = F * bCommonDen(F);
    613661  g = G * bCommonDen(G);
     662  CanonicalForm contf= myicontent (f);
     663  CanonicalForm contg= myicontent (g);
     664  f /= contf;
     665  g /= contg;
     666  CanonicalForm gcdcfcg= myicontent (contf, contg);
    614667  Variable a, b;
    615668  if(hasFirstAlgVar(f,a))
     
    627680      Off( SW_RATIONAL );
    628681      Off( SW_USE_QGCD );
    629       tmp = gcd( F, G );
     682      tmp = gcdcfcg*gcd( f, g );
    630683      On( SW_USE_QGCD );
    631684      if (off_rational) Off(SW_RATIONAL);
     
    682735      if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
    683736      setCharacteristic(0);
    684       return CanonicalForm(1);
     737      return gcdcfcg;
    685738    }
    686739    setCharacteristic(0);
     
    712765        setReduce(a,true);
    713766        if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
    714         return tmp;
     767        return tmp*gcdcfcg;
    715768      }
    716769      Off( SW_RATIONAL );
     
    729782  setReduce(a,true);
    730783  Off( SW_USE_QGCD );
    731   D = gcd( f, g );
     784  D = gcdcfcg*gcd( f, g );
    732785  On( SW_USE_QGCD );
    733786  if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
  • factory/cfNewtonPolygon.cc

    ra03496 re7676a  
    222222}
    223223
     224int **
     225merge (int ** points1, int sizePoints1, int ** points2, int sizePoints2,
     226       int& sizeResult)
     227{
     228  int i, j;
     229  sizeResult= sizePoints1+sizePoints2;
     230  for (i= 0; i < sizePoints1; i++)
     231  {
     232    for (j= 0; j < sizePoints2; j++)
     233    {
     234      if (points1[i][0] != points2[j][0])
     235        continue;
     236      else
     237      {
     238        if (points1[i][1] != points2[j][1])
     239          continue;
     240        else
     241        {
     242          points2[j][0]= -1;
     243          points2[j][1]= -1;
     244          sizeResult--;
     245        }
     246      }
     247    }
     248  }
     249  if (sizeResult == 0)
     250    return points1;
     251
     252  int ** result= new int *[sizeResult];
     253  for (i= 0; i < sizeResult; i++)
     254    result [i]= new int [2];
     255
     256  int k= 0;
     257  for (i= 0; i < sizePoints1; i++, k++)
     258  {
     259    result[k][0]= points1[i][0];
     260    result[k][1]= points1[i][1];
     261  }
     262  for (i= 0; i < sizePoints2; i++)
     263  {
     264    if (points2[i][0] < 0)
     265      continue;
     266    else
     267    {
     268      result[k][0]= points2[i][0];
     269      result[k][1]= points2[i][1];
     270      k++;
     271    }
     272  }
     273  return result;
     274}
     275
    224276// assumes a bivariate poly as input
    225277int ** newtonPolygon (const CanonicalForm& F, int& sizeOfNewtonPoly)
     
    257309    delete [] points[i];
    258310  delete [] points;
     311
     312  return result;
     313}
     314
     315// assumes a bivariate polys as input
     316int ** newtonPolygon (const CanonicalForm& F, const CanonicalForm& G,
     317                      int& sizeOfNewtonPoly)
     318{
     319  int sizeF= size (F);
     320  int ** pointsF= new int* [sizeF];
     321  for (int i= 0; i < sizeF; i++)
     322    pointsF [i]= new int [2];
     323  int j= 0;
     324  int * buf;
     325  int bufSize;
     326  for (CFIterator i= F; i.hasTerms(); i++)
     327  {
     328    buf= getDegrees (i.coeff(), bufSize);
     329    for (int k= 0; k < bufSize; k++, j++)
     330    {
     331      pointsF [j] [0]= i.exp();
     332      pointsF [j] [1]= buf [k];
     333    }
     334    delete [] buf;
     335  }
     336
     337  int sizeG= size (G);
     338  int ** pointsG= new int* [sizeG];
     339  for (int i= 0; i < sizeG; i++)
     340    pointsG [i]= new int [2];
     341  j= 0;
     342  for (CFIterator i= G; i.hasTerms(); i++)
     343  {
     344    buf= getDegrees (i.coeff(), bufSize);
     345    for (int k= 0; k < bufSize; k++, j++)
     346    {
     347      pointsG [j] [0]= i.exp();
     348      pointsG [j] [1]= buf [k];
     349    }
     350    delete [] buf;
     351  }
     352
     353  int sizePoints;
     354  int ** points= merge (pointsF, sizeF, pointsG, sizeG, sizePoints);
     355
     356  int n= polygon (points, sizePoints);
     357
     358  int ** result= new int* [n];
     359  for (int i= 0; i < n; i++)
     360  {
     361    result [i]= new int [2];
     362    result [i] [0]= points [i] [0];
     363    result [i] [1]= points [i] [1];
     364  }
     365
     366  sizeOfNewtonPoly= n;
     367  for (int i= 0; i < sizeF; i++)
     368    delete [] pointsF[i];
     369  delete [] pointsF;
     370  for (int i= 0; i < sizeG; i++)
     371    delete [] pointsG[i];
     372  delete [] pointsG;
    259373
    260374  return result;
     
    484598
    485599CanonicalForm
    486 compress (const CanonicalForm& F, mat_ZZ& M, vec_ZZ& A)
     600compress (const CanonicalForm& F, mat_ZZ& M, vec_ZZ& A, bool computeMA)
    487601{
    488602  int n;
    489   int ** newtonPolyg= newtonPolygon (F, n);
    490   convexDense (newtonPolyg, n, M, A);
     603  int ** newtonPolyg;
     604  if (computeMA)
     605  {
     606    newtonPolyg= newtonPolygon (F, n);
     607    convexDense (newtonPolyg, n, M, A);
     608  }
    491609  CanonicalForm result= 0;
    492610  ZZ expX, expY;
     
    565683  }
    566684
    567   for (int i= 0; i < n; i++)
    568     delete [] newtonPolyg [i];
    569   delete [] newtonPolyg;
    570 
    571   M= inv (M);
     685  if (computeMA)
     686  {
     687    for (int i= 0; i < n; i++)
     688      delete [] newtonPolyg [i];
     689    delete [] newtonPolyg;
     690    M= inv (M);
     691  }
     692
    572693  return result;
    573694}
  • factory/cfNewtonPolygon.h

    ra03496 re7676a  
    4040                     );
    4141
     42/// compute the convex hull of the support of two bivariate polynomials
     43///
     44/// @return an array of points in the plane which are the vertices of the convex
     45///         hull of the support of F and G
     46int ** newtonPolygon (const CanonicalForm& F,///< [in] a bivariate polynomial
     47                      const CanonicalForm& G,///< [in] a bivariate polynomial
     48                      int& sizeOfNewtonPoly  ///< [in, out] size of the result
     49                     );
     50
    4251/// check if @a point is inside a polygon described by points
    4352///
     
    7685compress (const CanonicalForm& F, ///< [in] compressed, i.e. F.level()==2,
    7786                                  ///< bivariate poly
    78           mat_ZZ& inverseM,       ///< [in,out] returns the inverse of M
    79           vec_ZZ& A               ///< [in,out] returns translation
     87          mat_ZZ& inverseM,       ///< [in,out] returns the inverse of M,
     88                                  ///< if computeMA==true, M otherwise
     89          vec_ZZ& A,              ///< [in,out] returns translation
     90          bool computeMA= true    ///< [in] whether to compute M and A
    8091         );
    8192
  • factory/cf_gcd.cc

    ra03496 re7676a  
    757757  else if (!fc_and_gc_Univariate)
    758758  {
    759     if (
    760     isOn(SW_USE_CHINREM_GCD)
    761     && (isPurePoly_m(fc)) && (isPurePoly_m(gc))
    762     )
    763     {
    764     #if 0
    765       if ( p1 == fc.level() )
    766         fc = chinrem_gcd( fc, gc );
    767       else
    768       {
    769         fc = replacevar( fc, Variable(p1), Variable(mp) );
    770         gc = replacevar( gc, Variable(p1), Variable(mp) );
    771         fc = replacevar( chinrem_gcd( fc, gc ), Variable(mp), Variable(p1) );
    772       }
    773     #else
    774       fc = chinrem_gcd( fc, gc);
    775     #endif
    776     }
    777     else if ( isOn( SW_USE_EZGCD ) )
    778     {
    779       if ( pe == 1 )
     759    if ( isOn( SW_USE_EZGCD ) )
     760    {
     761      fc= ezgcd (fc, gc);
     762      /*if ( pe == 1 )
    780763        fc = ezgcd( fc, gc );
    781764      else if ( pe > 0 )// no variable at position 1
     
    791774        gc = swapvar( gc, Variable(pe), Variable(1) );
    792775        fc = swapvar( ezgcd( fc, gc ), Variable(1), Variable(pe) );
     776      }*/
     777    }
     778    else if (
     779    isOn(SW_USE_CHINREM_GCD)
     780    && (isPurePoly_m(fc)) && (isPurePoly_m(gc))
     781    )
     782    {
     783    #if 0
     784      if ( p1 == fc.level() )
     785        fc = chinrem_gcd( fc, gc );
     786      else
     787      {
     788        fc = replacevar( fc, Variable(p1), Variable(mp) );
     789        gc = replacevar( gc, Variable(p1), Variable(mp) );
     790        fc = replacevar( chinrem_gcd( fc, gc ), Variable(mp), Variable(p1) );
    793791      }
     792    #else
     793      fc = chinrem_gcd( fc, gc);
     794    #endif
    794795    }
    795796    else
     
    12361237
    12371238  CanonicalForm Dn, test= 0;
     1239  cl =  gcd (f.lc(),g.lc());
     1240  CanonicalForm gcdcfcg= gcd (cf, cg);
     1241  CanonicalForm b= 1;
     1242  int minCommonDeg= 0;
     1243  for (i= tmax (f.level(), g.level()); i > 0; i--)
     1244  {
     1245    if (degree (f, i) <= 0 || degree (g, i) <= 0)
     1246      continue;
     1247    else
     1248    {
     1249      minCommonDeg= tmin (degree (g, i), degree (f, i));
     1250      break;
     1251    }
     1252  }
     1253  if (i == 0)
     1254    return gcdcfcg;
     1255  for (; i > 0; i--)
     1256  {
     1257    if (degree (f, i) <= 0 || degree (g, i) <= 0)
     1258      continue;
     1259    else
     1260      minCommonDeg= tmin (minCommonDeg, tmin (degree (g, i), degree (f, i)));
     1261  }
     1262  b= 2*tmin (maxNorm (f), maxNorm (g))*abs (cl)*
     1263     power (CanonicalForm (2), minCommonDeg);
    12381264  bool equal= false;
    12391265  i = cf_getNumBigPrimes() - 1;
    1240   cl =  gcd (f.lc(),g.lc());
    1241 
    1242   CanonicalForm gcdcfcg= gcd (cf, cg);
     1266
     1267  CanonicalForm cof, cog, cofp, cogp, newCof, newCog, cofn, cogn;
    12431268  //Off (SW_RATIONAL);
    12441269  while ( true )
     
    12461271    p = cf_getBigPrime( i );
    12471272    i--;
    1248     while ( i >= 0 && mod( cl, p ) == 0 )
     1273    while ( i >= 0 && mod( cl*(lc(f)/cl)*(lc(g)/cl), p ) == 0 )
    12491274    {
    12501275      p = cf_getBigPrime( i );
     
    12531278    //printf("try p=%d\n",p);
    12541279    setCharacteristic( p );
    1255     Dp = gcd_poly( mapinto( f ), mapinto( g ) );
     1280    Dp = GCD_small_p (mapinto (f), mapinto (g), cofp, cogp);
    12561281    Dp /=Dp.lc();
     1282    cofp /= lc (cofp);
     1283    cogp /= lc (cogp);
    12571284    setCharacteristic( 0 );
    12581285    dp_deg=totaldegree(Dp);
     
    12651292    {
    12661293      D = mapinto( Dp );
     1294      cof= mapinto (cofp);
     1295      cog= mapinto (cogp);
    12671296      d_deg=dp_deg;
    12681297      q = p;
     
    12731302      {
    12741303        chineseRemainder( D, q, mapinto( Dp ), p, newD, newq );
     1304        chineseRemainder( cof, q, mapinto (cofp), p, newCof, newq);
     1305        chineseRemainder( cog, q, mapinto (cogp), p, newCog, newq);
     1306        cof= newCof;
     1307        cog= newCog;
    12751308        q = newq;
    12761309        D = newD;
     
    12821315        q = p;
    12831316        D = mapinto( Dp );
     1317        cof= mapinto (cof);
     1318        cog= mapinto (cog);
    12841319        d_deg=dp_deg;
    12851320        test= 0;
     
    12951330    {
    12961331      Dn= Farey(D,q);
     1332      cofn= Farey(cof,q);
     1333      cogn= Farey(cog,q);
    12971334      int is_rat= isOn (SW_RATIONAL);
    12981335      On (SW_RATIONAL);
    12991336      cd = bCommonDen( Dn ); // we need On(SW_RATIONAL)
     1337      cofn *= bCommonDen (cofn);
     1338      cogn *= bCommonDen (cogn);
    13001339      if (!is_rat)
    13011340        Off (SW_RATIONAL);
     
    13061345        equal= true;
    13071346      //Dn /=vcontent(Dn,Variable(1));
    1308       if (equal && fdivides( Dn, f ) && fdivides( Dn, g ) )
     1347      if ((terminationTest (f,g, cofn, cogn, Dn)) ||
     1348          ((equal || q > b) && fdivides (Dn, f) && fdivides (Dn, g)))
    13091349      {
    13101350        //printf(" -> success\n");
     
    13251365}
    13261366
     1367
  • factory/cf_gcd_smallp.cc

    ra03496 re7676a  
    3434#include "facHensel.h"
    3535#include "cf_iter.h"
     36#include "cfNewtonPolygon.h"
    3637
    3738// iinline helper functions:
     
    4950TIMING_DEFINE_PRINT(gcd_recursion)
    5051TIMING_DEFINE_PRINT(newton_interpolation)
     52
     53bool
     54terminationTest (const CanonicalForm& F, const CanonicalForm& G,
     55                 const CanonicalForm& coF, const CanonicalForm& coG,
     56                 const CanonicalForm& cand)
     57{
     58  CanonicalForm LCCand= abs (LC (cand));
     59  if (LCCand*abs (LC (coF)) == abs (LC (F)))
     60  {
     61    if (LCCand*abs (LC (coG)) == abs (LC (G)))
     62    {
     63      if (abs (cand)*abs (coF) == abs (F))
     64      {
     65        if (abs (cand)*abs (coG) == abs (G))
     66          return true;
     67      }
     68      return false;
     69    }
     70    return false;
     71  }
     72  return false;
     73}
    5174
    5275static const double log2exp= 1.442695041;
     
    216239
    217240  return 1;
    218 }
    219 
    220 int
    221 substituteCheck (const CanonicalForm& F, const CanonicalForm& G)
    222 {
    223   if (F.inCoeffDomain() || G.inCoeffDomain())
    224     return 0;
    225   Variable x= Variable (1);
    226   if (degree (F, x) <= 1 || degree (G, x) <= 1)
    227     return 0;
    228   CanonicalForm f= swapvar (F, F.mvar(), x); //TODO swapping is pretty expensive
    229   CanonicalForm g= swapvar (G, G.mvar(), x);
    230   int sizef= 0;
    231   int sizeg= 0;
    232   for (CFIterator i= f; i.hasTerms(); i++, sizef++)
    233   {
    234     if (i.exp() == 1)
    235       return 0;
    236   }
    237   for (CFIterator i= g; i.hasTerms(); i++, sizeg++)
    238   {
    239     if (i.exp() == 1)
    240       return 0;
    241   }
    242   int * expf= new int [sizef];
    243   int * expg= new int [sizeg];
    244   int j= 0;
    245   for (CFIterator i= f; i.hasTerms(); i++, j++)
    246   {
    247     expf [j]= i.exp();
    248   }
    249   j= 0;
    250   for (CFIterator i= g; i.hasTerms(); i++, j++)
    251   {
    252     expg [j]= i.exp();
    253   }
    254 
    255   int indf= sizef - 1;
    256   int indg= sizeg - 1;
    257   if (expf[indf] == 0)
    258     indf--;
    259   if (expg[indg] == 0)
    260     indg--;
    261 
    262   if (expg[indg] != expf [indf] || (expg[indg] == 1 && expf[indf] == 1))
    263   {
    264     delete [] expg;
    265     delete [] expf;
    266     return 0;
    267   }
    268   // expf[indg] == expf[indf] after here
    269   int result= expg[indg];
    270   for (int i= indf - 1; i >= 0; i--)
    271   {
    272     if (expf [i]%result != 0)
    273     {
    274       delete [] expg;
    275       delete [] expf;
    276       return 0;
    277     }
    278   }
    279 
    280   for (int i= indg - 1; i >= 0; i--)
    281   {
    282     if (expg [i]%result != 0)
    283     {
    284       delete [] expg;
    285       delete [] expf;
    286       return 0;
    287     }
    288   }
    289 
    290   delete [] expg;
    291   delete [] expf;
    292   return result;
    293 }
    294 
    295 // substiution
    296 void
    297 subst (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& A,
    298        CanonicalForm& B, const int d
    299       )
    300 {
    301   if (d == 1)
    302   {
    303     A= F;
    304     B= G;
    305     return;
    306   }
    307 
    308   CanonicalForm C= 0;
    309   CanonicalForm D= 0;
    310   Variable x= Variable (1);
    311   CanonicalForm f= swapvar (F, x, F.mvar());
    312   CanonicalForm g= swapvar (G, x, G.mvar());
    313   for (CFIterator i= f; i.hasTerms(); i++)
    314     C += i.coeff()*power (f.mvar(), i.exp()/ d);
    315   for (CFIterator i= g; i.hasTerms(); i++)
    316     D += i.coeff()*power (g.mvar(), i.exp()/ d);
    317   A= swapvar (C, x, F.mvar());
    318   B= swapvar (D, x, G.mvar());
    319 }
    320 
    321 CanonicalForm
    322 reverseSubst (const CanonicalForm& F, const int d)
    323 {
    324   if (d == 1)
    325     return F;
    326 
    327   Variable x= Variable (1);
    328   if (degree (F, x) <= 0)
    329     return F;
    330   CanonicalForm f= swapvar (F, x, F.mvar());
    331   CanonicalForm result= 0;
    332   for (CFIterator i= f; i.hasTerms(); i++)
    333     result += i.coeff()*power (f.mvar(), d*i.exp());
    334   return swapvar (result, x, F.mvar());
    335241}
    336242
     
    541447}
    542448
     449CanonicalForm
     450GCD_Fp_extension (const CanonicalForm& F, const CanonicalForm& G,
     451                  CanonicalForm& coF, CanonicalForm& coG,
     452                  Variable & alpha, CFList& l, bool& topLevel);
     453
     454CanonicalForm
     455GCD_Fp_extension (const CanonicalForm& F, const CanonicalForm& G,
     456                  Variable & alpha, CFList& l, bool& topLevel)
     457{
     458  CanonicalForm dummy1, dummy2;
     459  CanonicalForm result= GCD_Fp_extension (F, G, dummy1, dummy2, alpha, l,
     460                                          topLevel);
     461  return result;
     462}
     463
    543464/// GCD of F and G over \f$ F_{p}(\alpha ) \f$ ,
    544465/// l and topLevel are only used internally, output is monic
     
    547468CanonicalForm
    548469GCD_Fp_extension (const CanonicalForm& F, const CanonicalForm& G,
     470                  CanonicalForm& coF, CanonicalForm& coG,
    549471                  Variable & alpha, CFList& l, bool& topLevel)
    550472{
    551473  CanonicalForm A= F;
    552474  CanonicalForm B= G;
    553   if (F.isZero() && degree(G) > 0) return G/Lc(G);
    554   else if (G.isZero() && degree (F) > 0) return F/Lc(F);
    555   else if (F.isZero() && G.isZero()) return F.genOne();
    556   if (F.inBaseDomain() || G.inBaseDomain()) return F.genOne();
    557   if (F.isUnivariate() && fdivides(F, G)) return F/Lc(F);
    558   if (G.isUnivariate() && fdivides(G, F)) return G/Lc(G);
    559   if (F == G) return F/Lc(F);
     475  if (F.isZero() && degree(G) > 0)
     476  {
     477    coF= 0;
     478    coG= Lc (G);
     479    return G/Lc(G);
     480  }
     481  else if (G.isZero() && degree (F) > 0)
     482  {
     483    coF= Lc (F);
     484    coG= 0;
     485    return F/Lc(F);
     486  }
     487  else if (F.isZero() && G.isZero())
     488  {
     489    coF= coG= 0;
     490    return F.genOne();
     491  }
     492  if (F.inBaseDomain() || G.inBaseDomain())
     493  {
     494    coF= F;
     495    coG= G;
     496    return F.genOne();
     497  }
     498  if (F.isUnivariate() && fdivides(F, G, coG))
     499  {
     500    coF= Lc (F);
     501    return F/Lc(F);
     502  }
     503  if (G.isUnivariate() && fdivides(G, F, coF))
     504  {
     505    coG= Lc (G);
     506    return G/Lc(G);
     507  }
     508  if (F == G)
     509  {
     510    coF= coG= Lc (F);
     511    return F/Lc(F);
     512  }
    560513
    561514  CFMap M,N;
    562515  int best_level= myCompress (A, B, M, N, topLevel);
    563516
    564   if (best_level == 0) return B.genOne();
     517  if (best_level == 0)
     518  {
     519    coF= F;
     520    coG= G;
     521    return B.genOne();
     522  }
    565523
    566524  A= M(A);
     
    571529  //univariate case
    572530  if (A.isUnivariate() && B.isUnivariate())
    573     return N (gcd(A,B));
    574 
    575   int substitute= substituteCheck (A, B);
    576 
    577   if (substitute > 1)
    578     subst (A, B, A, B, substitute);
     531  {
     532    CanonicalForm result= gcd (A, B);
     533    coF= N (A/result);
     534    coG= N (B/result);
     535    return N (result);
     536  }
    579537
    580538  CanonicalForm cA, cB;    // content of A and B
     
    598556  }
    599557
     558  int sizeNewtonPolyg;
     559  int ** newtonPolyg= NULL;
     560  mat_ZZ MM;
     561  vec_ZZ V;
     562  bool compressConvexDense= (ppA.level() == 2 && ppB.level() == 2);
     563  if (compressConvexDense)
     564  {
     565    CanonicalForm bufcA= cA;
     566    CanonicalForm bufcB= cB;
     567    cA= content (ppA, 1);
     568    cB= content (ppB, 1);
     569    ppA /= cA;
     570    ppB /= cB;
     571    gcdcAcB *= gcd (cA, cB);
     572    cA *= bufcA;
     573    cB *= bufcB;
     574    if (ppA.isUnivariate() || ppB.isUnivariate())
     575    {
     576      if (ppA.level() == ppB.level())
     577      {
     578        CanonicalForm result= gcd (ppA, ppB);
     579        coF= N ((ppA/result)*(cA/gcdcAcB));
     580        coG= N ((ppB/result)*(cB/gcdcAcB));
     581        return N (result*gcdcAcB);
     582      }
     583      else
     584      {
     585        coF= N (ppA*(cA/gcdcAcB));
     586        coG= N (ppB*(cB/gcdcAcB));
     587        return N (gcdcAcB);
     588      }
     589    }
     590
     591    newtonPolyg= newtonPolygon (ppA,ppB, sizeNewtonPolyg);
     592    convexDense (newtonPolyg, sizeNewtonPolyg, MM, V);
     593
     594    for (int i= 0; i < sizeNewtonPolyg; i++)
     595      delete [] newtonPolyg[i];
     596    delete [] newtonPolyg;
     597
     598    ppA= compress (ppA, MM, V, false);
     599    ppB= compress (ppB, MM, V, false);
     600    MM= inv (MM);
     601
     602    if (ppA.isUnivariate() && ppB.isUnivariate())
     603    {
     604      if (ppA.level() == ppB.level())
     605      {
     606        CanonicalForm result= gcd (ppA, ppB);
     607        coF= N (decompress ((ppA/result), MM, V)*(cA/gcdcAcB));
     608        coG= N (decompress ((ppB/result), MM, V)*(cB/gcdcAcB));
     609        return N (decompress (result, MM, V)*gcdcAcB);
     610      }
     611      else
     612      {
     613        coF= N (decompress (ppA, MM, V));
     614        coG= N (decompress (ppB, MM, V));
     615        return N (gcdcAcB);
     616      }
     617    }
     618  }
     619
    600620  CanonicalForm lcA, lcB;  // leading coefficients of A and B
    601621  CanonicalForm gcdlcAlcB;
     
    604624  lcB= uni_lcoeff (ppB);
    605625
    606   if (fdivides (lcA, lcB))
     626  /*if (fdivides (lcA, lcB))
    607627  {
    608628    if (fdivides (A, B))
     
    613633    if (fdivides (B, A))
    614634      return G/Lc(G);
    615   }
     635  }*/
    616636
    617637  gcdlcAlcB= gcd (lcA, lcB);
     
    621641  if (d == 0)
    622642  {
    623     if (substitute > 1)
    624       return N (reverseSubst (gcdcAcB, substitute));
    625     else
    626       return N(gcdcAcB);
    627   }
     643    coF= N (ppA*(cA/gcdcAcB));
     644    coG= N (ppB*(cB/gcdcAcB));
     645    return N(gcdcAcB);
     646  }
     647
    628648  int d0= totaldegree (ppB, Variable(2), Variable (ppB.level()));
    629649  if (d0 < d)
     
    631651  if (d == 0)
    632652  {
    633     if (substitute > 1)
    634       return N (reverseSubst (gcdcAcB, substitute));
    635     else
    636       return N(gcdcAcB);
     653    coF= N (ppA*(cA/gcdcAcB));
     654    coG= N (ppB*(cB/gcdcAcB));
     655    return N(gcdcAcB);
    637656  }
    638657
    639658  CanonicalForm m, random_element, G_m, G_random_element, H, cH, ppH;
    640   CanonicalForm newtonPoly;
     659  CanonicalForm newtonPoly, coF_random_element, coG_random_element, coF_m,
     660                coG_m, ppCoF, ppCoG;
    641661
    642662  newtonPoly= 1;
    643663  m= gcdlcAlcB;
    644664  G_m= 0;
     665  coF= 0;
     666  coG= 0;
    645667  H= 0;
    646668  bool fail= false;
     
    650672  CanonicalForm prim_elem, im_prim_elem;
    651673  CFList source, dest;
     674  int bound1= degree (ppA, 1);
     675  int bound2= degree (ppB, 1);
    652676  do
    653677  {
    654     random_element= randomElement (m, V_buf, l, fail);
     678    random_element= randomElement (m*lcA*lcB, V_buf, l, fail);
    655679    if (fail)
    656680    {
     
    667691      {
    668692        m= mapDown (m, prim_elem, im_prim_elem, alpha, source, dest);
    669         G_m= mapDown (m, prim_elem, im_prim_elem, alpha, source, dest);
     693        G_m= mapDown (G_m, prim_elem, im_prim_elem, alpha, source, dest);
     694        coF_m= mapDown (coF_m, prim_elem, im_prim_elem, alpha, source, dest);
     695        coG_m= mapDown (coG_m, prim_elem, im_prim_elem, alpha, source, dest);
    670696        newtonPoly= mapDown (newtonPoly, prim_elem, im_prim_elem, alpha,
    671697                             source, dest);
     
    674700        gcdlcAlcB= mapDown (gcdlcAlcB, prim_elem, im_prim_elem, alpha,
    675701                            source, dest);
     702        lcA= mapDown (lcA, prim_elem, im_prim_elem, alpha, source, dest);
     703        lcB= mapDown (lcB, prim_elem, im_prim_elem, alpha, source, dest);
    676704        for (CFListIterator i= l; i.hasItem(); i++)
    677705          i.getItem()= mapDown (i.getItem(), prim_elem, im_prim_elem, alpha,
     
    693721      m= mapUp (m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
    694722      G_m= mapUp (G_m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
     723      coF_m= mapUp (coF_m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
     724      coG_m= mapUp (coG_m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
    695725      newtonPoly= mapUp (newtonPoly, alpha, V_buf, prim_elem, im_prim_elem,
    696726                          source, dest);
     
    699729      gcdlcAlcB= mapUp (gcdlcAlcB, alpha, V_buf, prim_elem, im_prim_elem,
    700730                         source, dest);
     731      lcA= mapUp (lcA, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
     732      lcB= mapUp (lcB, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
    701733
    702734      fail= false;
    703       random_element= randomElement (m, V_buf, l, fail );
     735      random_element= randomElement (m*lcA*lcB, V_buf, l, fail );
    704736      DEBOUTLN (cerr, "fail= " << fail);
    705737      CFList list;
    706738      TIMING_START (gcd_recursion);
    707739      G_random_element=
    708       GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x), V_buf,
     740      GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x),
     741                        coF_random_element, coG_random_element, V_buf,
    709742                        list, topLevel);
    710743      TIMING_END_AND_PRINT (gcd_recursion,
     
    717750      TIMING_START (gcd_recursion);
    718751      G_random_element=
    719       GCD_Fp_extension (ppA(random_element, x), ppB(random_element, x), V_buf,
     752      GCD_Fp_extension (ppA(random_element, x), ppB(random_element, x),
     753                        coF_random_element, coG_random_element, V_buf,
    720754                        list, topLevel);
    721755      TIMING_END_AND_PRINT (gcd_recursion,
     
    732766    if (d0 == 0)
    733767    {
    734       if (substitute > 1)
    735         return N (reverseSubst (gcdcAcB, substitute));
    736       else
    737         return N(gcdcAcB);
     768      coF= N (ppA*(cA/gcdcAcB));
     769      coG= N (ppB*(cB/gcdcAcB));
     770      return N(gcdcAcB);
    738771    }
    739772    if (d0 >  d)
     
    747780    (gcdlcAlcB(random_element, x)/uni_lcoeff (G_random_element))
    748781    * G_random_element;
     782    coF_random_element= (lcA(random_element,x)/uni_lcoeff(coF_random_element))
     783                        *coF_random_element;
     784    coG_random_element= (lcB(random_element,x)/uni_lcoeff(coG_random_element))
     785                        *coG_random_element;
    749786
    750787    if (!G_random_element.inCoeffDomain())
     
    760797      G_m= 0;
    761798      d= d0;
     799      coF_m= 0;
     800      coG_m= 0;
    762801    }
    763802
    764803    TIMING_START (newton_interpolation);
    765804    H= newtonInterp (random_element, G_random_element, newtonPoly, G_m, x);
     805    coF= newtonInterp (random_element, coF_random_element, newtonPoly, coF_m,x);
     806    coG= newtonInterp (random_element, coG_random_element, newtonPoly, coG_m,x);
    766807    TIMING_END_AND_PRINT (newton_interpolation,
    767808                          "time for newton interpolation: ");
    768809
    769810    //termination test
    770     if (uni_lcoeff (H) == gcdlcAlcB)
    771     {
    772       cH= uni_content (H);
     811    if ((uni_lcoeff (H) == gcdlcAlcB) || (G_m == H))
     812    {
     813      if (gcdlcAlcB.isOne())
     814        cH= 1;
     815      else
     816        cH= uni_content (H);
    773817      ppH= H/cH;
     818      CanonicalForm lcppH= gcdlcAlcB/cH;
     819      CanonicalForm ccoF= lcA/lcppH;
     820      ccoF /= Lc (ccoF);
     821      CanonicalForm ccoG= lcB/lcppH;
     822      ccoG /= Lc (ccoG);
     823      ppCoF= coF/ccoF;
     824      ppCoG= coG/ccoG;
    774825      if (inextension)
    775826      {
    776         CFList u, v;
    777         //maybe it's better to test if ppH is an element of F(\alpha) before
    778         //mapping down
    779         DEBOUTLN (cerr, "ppH before mapDown= " << ppH);
    780         ppH= mapDown (ppH, prim_elem, im_prim_elem, alpha, u, v);
    781         ppH /= Lc(ppH);
    782         DEBOUTLN (cerr, "ppH after mapDown= " << ppH);
    783         if (fdivides (ppH, A) && fdivides (ppH, B))
    784         {
    785           if (substitute > 1)
     827        if (((degree (ppCoF,1)+degree (ppH,1) == bound1) &&
     828             (degree (ppCoG,1)+degree (ppH,1) == bound2) &&
     829             terminationTest (ppA, ppB, ppCoF, ppCoG, ppH)) ||
     830             (fdivides (ppH, ppA, ppCoF) && fdivides (ppH, ppB, ppCoG)))
     831        {
     832          CFList u, v;
     833          DEBOUTLN (cerr, "ppH before mapDown= " << ppH);
     834          ppH= mapDown (ppH, prim_elem, im_prim_elem, alpha, u, v);
     835          ppCoF= mapDown (ppCoF, prim_elem, im_prim_elem, alpha, u, v);
     836          ppCoF= mapDown (ppCoG, prim_elem, im_prim_elem, alpha, u, v);
     837          ppH /= Lc(ppH);
     838          DEBOUTLN (cerr, "ppH after mapDown= " << ppH);
     839          if (compressConvexDense)
    786840          {
    787             ppH= reverseSubst (ppH, substitute);
    788             gcdcAcB= reverseSubst (gcdcAcB, substitute);
     841            ppH= decompress (ppH, MM, V);
     842            ppCoF= decompress (ppCoF, MM, V);
     843            ppCoG= decompress (ppCoG, MM, V);
    789844          }
     845          coF= N ((cA/gcdcAcB)*ppCoF);
     846          coG= N ((cB/gcdcAcB)*ppCoG);
    790847          return N(gcdcAcB*ppH);
    791848        }
    792849      }
    793       else if (fdivides (ppH, A) && fdivides (ppH, B))
    794       {
    795         if (substitute > 1)
    796         {
    797           ppH= reverseSubst (ppH, substitute);
    798           gcdcAcB= reverseSubst (gcdcAcB, substitute);
     850      else if (((degree (ppCoF,1)+degree (ppH,1) == bound1) &&
     851                (degree (ppCoG,1)+degree (ppH,1) == bound2) &&
     852                terminationTest (ppA, ppB, ppCoF, ppCoG, ppH)) ||
     853                (fdivides (ppH, ppA, ppCoF) && fdivides (ppH, ppB, ppCoG)))
     854      {
     855        if (compressConvexDense)
     856        {
     857          ppH= decompress (ppH, MM, V);
     858          ppCoF= decompress (ppCoF, MM, V);
     859          ppCoG= decompress (ppCoG, MM, V);
    799860        }
     861        coF= N ((cA/gcdcAcB)*ppCoF);
     862        coG= N ((cB/gcdcAcB)*ppCoG);;
    800863        return N(gcdcAcB*ppH);
    801864      }
     
    803866
    804867    G_m= H;
     868    coF_m= coF;
     869    coG_m= coG;
    805870    newtonPoly= newtonPoly*(x - random_element);
    806871    m= m*(x - random_element);
     
    848913}
    849914
     915CanonicalForm
     916GCD_GF (const CanonicalForm& F, const CanonicalForm& G,
     917        CanonicalForm& coF, CanonicalForm& coG,
     918        CFList& l, bool& topLevel);
     919
     920CanonicalForm
     921GCD_GF (const CanonicalForm& F, const CanonicalForm& G, CFList& l,
     922        bool& topLevel)
     923{
     924  CanonicalForm dummy1, dummy2;
     925  CanonicalForm result= GCD_GF (F, G, dummy1, dummy2, l, topLevel);
     926  return result;
     927}
     928
    850929/// GCD of F and G over GF, based on Alg. 7.2. as described in "Algorithms for
    851930/// Computer Algebra" by Geddes, Czapor, Labahn
     
    853932/// faster field arithmetics, however it might fail if the input is large since
    854933/// the size of the base field is bounded by 2^16, output is monic
    855 CanonicalForm GCD_GF (const CanonicalForm& F, const CanonicalForm& G,
     934CanonicalForm
     935GCD_GF (const CanonicalForm& F, const CanonicalForm& G,
     936        CanonicalForm& coF, CanonicalForm& coG,
    856937        CFList& l, bool& topLevel)
    857938{
    858939  CanonicalForm A= F;
    859940  CanonicalForm B= G;
    860   if (F.isZero() && degree(G) > 0) return G/Lc(G);
    861   else if (G.isZero() && degree (F) > 0) return F/Lc(F);
    862   else if (F.isZero() && G.isZero()) return F.genOne();
    863   if (F.inBaseDomain() || G.inBaseDomain()) return F.genOne();
    864   if (F.isUnivariate() && fdivides(F, G)) return F/Lc(F);
    865   if (G.isUnivariate() && fdivides(G, F)) return G/Lc(G);
    866   if (F == G) return F/Lc(F);
     941  if (F.isZero() && degree(G) > 0)
     942  {
     943    coF= 0;
     944    coG= Lc (G);
     945    return G/Lc(G);
     946  }
     947  else if (G.isZero() && degree (F) > 0)
     948  {
     949    coF= Lc (F);
     950    coG= 0;
     951    return F/Lc(F);
     952  }
     953  else if (F.isZero() && G.isZero())
     954  {
     955    coF= coG= 0;
     956    return F.genOne();
     957  }
     958  if (F.inBaseDomain() || G.inBaseDomain())
     959  {
     960    coF= F;
     961    coG= G;
     962    return F.genOne();
     963  }
     964  if (F.isUnivariate() && fdivides(F, G, coG))
     965  {
     966    coF= Lc (F);
     967    return F/Lc(F);
     968  }
     969  if (G.isUnivariate() && fdivides(G, F, coF))
     970  {
     971    coG= Lc (G);
     972    return G/Lc(G);
     973  }
     974  if (F == G)
     975  {
     976    coF= coG= Lc (F);
     977    return F/Lc(F);
     978  }
    867979
    868980  CFMap M,N;
    869981  int best_level= myCompress (A, B, M, N, topLevel);
    870982
    871   if (best_level == 0) return B.genOne();
     983  if (best_level == 0)
     984  {
     985    coF= F;
     986    coG= G;
     987    return B.genOne();
     988  }
    872989
    873990  A= M(A);
     
    878995  //univariate case
    879996  if (A.isUnivariate() && B.isUnivariate())
    880     return N (gcd (A, B));
    881 
    882   int substitute= substituteCheck (A, B);
    883 
    884   if (substitute > 1)
    885     subst (A, B, A, B, substitute);
     997  {
     998    CanonicalForm result= gcd (A, B);
     999    coF= N (A/result);
     1000    coG= N (B/result);
     1001    return N (result);
     1002  }
    8861003
    8871004  CanonicalForm cA, cB;    // content of A and B
     
    9051022  }
    9061023
     1024  int sizeNewtonPolyg;
     1025  int ** newtonPolyg= NULL;
     1026  mat_ZZ MM;
     1027  vec_ZZ V;
     1028  bool compressConvexDense= (ppA.level() == 2 && ppB.level() == 2);
     1029  if (compressConvexDense)
     1030  {
     1031    CanonicalForm bufcA= cA;
     1032    CanonicalForm bufcB= cB;
     1033    cA= content (ppA, 1);
     1034    cB= content (ppB, 1);
     1035    ppA /= cA;
     1036    ppB /= cB;
     1037    gcdcAcB *= gcd (cA, cB);
     1038    cA *= bufcA;
     1039    cB *= bufcB;
     1040    if (ppA.isUnivariate() || ppB.isUnivariate())
     1041    {
     1042      if (ppA.level() == ppB.level())
     1043      {
     1044        CanonicalForm result= gcd (ppA, ppB);
     1045        coF= N ((ppA/result)*(cA/gcdcAcB));
     1046        coG= N ((ppB/result)*(cB/gcdcAcB));
     1047        return N (result*gcdcAcB);
     1048      }
     1049      else
     1050      {
     1051        coF= N (ppA*(cA/gcdcAcB));
     1052        coG= N (ppB*(cB/gcdcAcB));
     1053        return N (gcdcAcB);
     1054      }
     1055    }
     1056
     1057    newtonPolyg= newtonPolygon (ppA,ppB, sizeNewtonPolyg);
     1058    convexDense (newtonPolyg, sizeNewtonPolyg, MM, V);
     1059
     1060    for (int i= 0; i < sizeNewtonPolyg; i++)
     1061      delete [] newtonPolyg[i];
     1062    delete [] newtonPolyg;
     1063
     1064    ppA= compress (ppA, MM, V, false);
     1065    ppB= compress (ppB, MM, V, false);
     1066    MM= inv (MM);
     1067
     1068    if (ppA.isUnivariate() && ppB.isUnivariate())
     1069    {
     1070      if (ppA.level() == ppB.level())
     1071      {
     1072        CanonicalForm result= gcd (ppA, ppB);
     1073        coF= N (decompress ((ppA/result), MM, V)*(cA/gcdcAcB));
     1074        coG= N (decompress ((ppB/result), MM, V)*(cB/gcdcAcB));
     1075        return N (decompress (result, MM, V)*gcdcAcB);
     1076      }
     1077      else
     1078      {
     1079        coF= N (decompress (ppA, MM, V));
     1080        coG= N (decompress (ppB, MM, V));
     1081        return N (gcdcAcB);
     1082      }
     1083    }
     1084  }
     1085
    9071086  CanonicalForm lcA, lcB;  // leading coefficients of A and B
    9081087  CanonicalForm gcdlcAlcB;
     
    9111090  lcB= uni_lcoeff (ppB);
    9121091
    913   if (fdivides (lcA, lcB))
    914   {
    915     if (fdivides (A, B))
     1092  /*if (fdivides (lcA, lcB))
     1093  {
     1094    if (fdivides (ppA, ppB, coG))
     1095    {
     1096      coF= 1;
     1097      if (compressConvexDense)
     1098        coG= decompress (coG, MM, V);
     1099      coG= N (coG*(cB/gcdcAcB));
    9161100      return F;
     1101    }
    9171102  }
    9181103  if (fdivides (lcB, lcA))
    9191104  {
    920     if (fdivides (B, A))
     1105    if (fdivides (ppB, ppA, coF))
     1106    {
     1107      coG= 1;
     1108      if (compressConvexDense)
     1109        coF= decompress (coF, MM, V);
     1110      coF= N (coF*(cA/gcdcAcB));
    9211111      return G;
    922   }
     1112    }
     1113  }*/
    9231114
    9241115  gcdlcAlcB= gcd (lcA, lcB);
     
    9271118  if (d == 0)
    9281119  {
    929     if (substitute > 1)
    930       return N (reverseSubst (gcdcAcB, substitute));
    931     else
    932       return N(gcdcAcB);
     1120    coF= N (ppA*(cA/gcdcAcB));
     1121    coG= N (ppB*(cB/gcdcAcB));
     1122    return N(gcdcAcB);
    9331123  }
    9341124  int d0= totaldegree (ppB, Variable(2), Variable (ppB.level()));
     
    9371127  if (d == 0)
    9381128  {
    939     if (substitute > 1)
    940       return N (reverseSubst (gcdcAcB, substitute));
    941     else
    942       return N(gcdcAcB);
     1129    coF= N (ppA*(cA/gcdcAcB));
     1130    coG= N (ppB*(cB/gcdcAcB));
     1131    return N(gcdcAcB);
    9431132  }
    9441133
    9451134  CanonicalForm m, random_element, G_m, G_random_element, H, cH, ppH;
    946   CanonicalForm newtonPoly;
     1135  CanonicalForm newtonPoly, coF_random_element, coG_random_element, coF_m,
     1136                coG_m, ppCoF, ppCoG;
    9471137
    9481138  newtonPoly= 1;
    9491139  m= gcdlcAlcB;
    9501140  G_m= 0;
     1141  coF= 0;
     1142  coG= 0;
    9511143  H= 0;
    9521144  bool fail= false;
    953   topLevel= false;
     1145  //topLevel= false;
    9541146  bool inextension= false;
    9551147  int p=-1;
     
    9581150  int expon;
    9591151  char gf_name_buf= gf_name;
     1152  int bound1= degree (ppA, 1);
     1153  int bound2= degree (ppB, 1);
    9601154  do
    9611155  {
    962     random_element= GFRandomElement (m, l, fail);
     1156    random_element= GFRandomElement (m*lcA*lcB, l, fail);
    9631157    if (fail)
    9641158    {
     
    9811175      G_m= GFMapUp (G_m, kk);
    9821176      newtonPoly= GFMapUp (newtonPoly, kk);
     1177      coF_m= GFMapUp (coF_m, kk);
     1178      coG_m= GFMapUp (coG_m, kk);
    9831179      ppA= GFMapUp (ppA, kk);
    9841180      ppB= GFMapUp (ppB, kk);
    9851181      gcdlcAlcB= GFMapUp (gcdlcAlcB, kk);
    986       random_element= GFRandomElement (m, l, fail);
     1182      lcA= GFMapUp (lcA, kk);
     1183      lcB= GFMapUp (lcB, kk);
     1184      random_element= GFRandomElement (m*lcA*lcB, l, fail);
    9871185      DEBOUTLN (cerr, "fail= " << fail);
    9881186      CFList list;
    9891187      TIMING_START (gcd_recursion);
    9901188      G_random_element= GCD_GF (ppA(random_element, x), ppB(random_element, x),
     1189                                coF_random_element, coG_random_element,
    9911190                                list, topLevel);
    9921191      TIMING_END_AND_PRINT (gcd_recursion,
     
    9991198      TIMING_START (gcd_recursion);
    10001199      G_random_element= GCD_GF (ppA(random_element, x), ppB(random_element, x),
     1200                                coF_random_element, coG_random_element,
    10011201                                list, topLevel);
    10021202      TIMING_END_AND_PRINT (gcd_recursion,
     
    10141214    {
    10151215      if (inextension)
    1016       {
    10171216        setCharacteristic (p, k, gf_name_buf);
    1018         {
    1019           if (substitute > 1)
    1020             return N (reverseSubst (gcdcAcB, substitute));
    1021           else
    1022             return N(gcdcAcB);
    1023         }
    1024       }
    1025       else
    1026       {
    1027         if (substitute > 1)
    1028           return N (reverseSubst (gcdcAcB, substitute));
    1029         else
    1030           return N(gcdcAcB);
    1031       }
     1217      coF= N (ppA*(cA/gcdcAcB));
     1218      coG= N (ppB*(cB/gcdcAcB));
     1219      return N(gcdcAcB);
    10321220    }
    10331221    if (d0 >  d)
     
    10411229    (gcdlcAlcB(random_element, x)/uni_lcoeff(G_random_element)) *
    10421230     G_random_element;
     1231
     1232    coF_random_element= (lcA(random_element,x)/uni_lcoeff(coF_random_element))
     1233                        *coF_random_element;
     1234    coG_random_element= (lcB(random_element,x)/uni_lcoeff(coG_random_element))
     1235                        *coG_random_element;
     1236
    10431237    if (!G_random_element.inCoeffDomain())
    10441238      d0= totaldegree (G_random_element, Variable(2),
     
    10531247      G_m= 0;
    10541248      d= d0;
     1249      coF_m= 0;
     1250      coG_m= 0;
    10551251    }
    10561252
    10571253    TIMING_START (newton_interpolation);
    10581254    H= newtonInterp (random_element, G_random_element, newtonPoly, G_m, x);
    1059     TIMING_END_AND_PRINT (newton_interpolation, "time for newton interpolation: ");
     1255    coF= newtonInterp (random_element, coF_random_element, newtonPoly, coF_m,x);
     1256    coG= newtonInterp (random_element, coG_random_element, newtonPoly, coG_m,x);
     1257    TIMING_END_AND_PRINT (newton_interpolation,
     1258                          "time for newton interpolation: ");
    10601259
    10611260    //termination test
    1062     if (uni_lcoeff (H) == gcdlcAlcB)
    1063     {
    1064       cH= uni_content (H);
     1261    if ((uni_lcoeff (H) == gcdlcAlcB) || (G_m == H))
     1262    {
     1263      if (gcdlcAlcB.isOne())
     1264        cH= 1;
     1265      else
     1266        cH= uni_content (H);
    10651267      ppH= H/cH;
     1268      CanonicalForm lcppH= gcdlcAlcB/cH;
     1269      CanonicalForm ccoF= lcA/lcppH;
     1270      ccoF /= Lc (ccoF);
     1271      CanonicalForm ccoG= lcB/lcppH;
     1272      ccoG /= Lc (ccoG);
     1273      ppCoF= coF/ccoF;
     1274      ppCoG= coG/ccoG;
    10661275      if (inextension)
    10671276      {
    1068         if (fdivides(ppH, GFMapUp(A, k)) && fdivides(ppH, GFMapUp(B,k)))
     1277        if (((degree (ppCoF,1)+degree (ppH,1) == bound1) &&
     1278             (degree (ppCoG,1)+degree (ppH,1) == bound2) &&
     1279             terminationTest (ppA, ppB, ppCoF, ppCoG, ppH)) ||
     1280             (fdivides (ppH, ppA, ppCoF) && fdivides (ppH, ppB, ppCoG)))
    10691281        {
    10701282          DEBOUTLN (cerr, "ppH before mapDown= " << ppH);
    10711283          ppH= GFMapDown (ppH, k);
     1284          ppCoF= GFMapDown (ppCoF, k);
     1285          ppCoG= GFMapDown (ppCoG, k);
    10721286          DEBOUTLN (cerr, "ppH after mapDown= " << ppH);
    1073           if (substitute > 1)
     1287          if (compressConvexDense)
    10741288          {
    1075             ppH= reverseSubst (ppH, substitute);
    1076             gcdcAcB= reverseSubst (gcdcAcB, substitute);
     1289            ppH= decompress (ppH, MM, V);
     1290            ppCoF= decompress (ppCoF, MM, V);
     1291            ppCoG= decompress (ppCoG, MM, V);
    10771292          }
     1293          coF= N ((cA/gcdcAcB)*ppCoF);
     1294          coG= N ((cB/gcdcAcB)*ppCoG);
    10781295          setCharacteristic (p, k, gf_name_buf);
    10791296          return N(gcdcAcB*ppH);
     
    10821299      else
    10831300      {
    1084         if (fdivides (ppH, A) && fdivides (ppH, B))
    1085         {
    1086           if (substitute > 1)
     1301      if (((degree (ppCoF,1)+degree (ppH,1) == bound1) &&
     1302           (degree (ppCoG,1)+degree (ppH,1) == bound2) &&
     1303           terminationTest (ppA, ppB, ppCoF, ppCoG, ppH)) ||
     1304           (fdivides (ppH, ppA, ppCoF) && fdivides (ppH, ppB, ppCoG)))
     1305        {
     1306          if (compressConvexDense)
    10871307          {
    1088             ppH= reverseSubst (ppH, substitute);
    1089             gcdcAcB= reverseSubst (gcdcAcB, substitute);
     1308            ppH= decompress (ppH, MM, V);
     1309            ppCoF= decompress (ppCoF, MM, V);
     1310            ppCoG= decompress (ppCoG, MM, V);
    10901311          }
     1312          coF= N ((cA/gcdcAcB)*ppCoF);
     1313          coG= N ((cB/gcdcAcB)*ppCoG);
    10911314          return N(gcdcAcB*ppH);
    10921315        }
     
    10951318
    10961319    G_m= H;
     1320    coF_m= coF;
     1321    coG_m= coG;
    10971322    newtonPoly= newtonPoly*(x - random_element);
    10981323    m= m*(x - random_element);
     
    11521377}
    11531378
    1154 CanonicalForm GCD_small_p (const CanonicalForm& F, const CanonicalForm&  G,
    1155                            bool& topLevel, CFList& l)
     1379CanonicalForm
     1380GCD_small_p (const CanonicalForm& F, const CanonicalForm&  G,
     1381             CanonicalForm& coF, CanonicalForm& coG,
     1382             bool& topLevel, CFList& l);
     1383
     1384CanonicalForm
     1385GCD_small_p (const CanonicalForm& F, const CanonicalForm& G,
     1386             bool& topLevel, CFList& l)
     1387{
     1388  CanonicalForm dummy1, dummy2;
     1389  CanonicalForm result= GCD_small_p (F, G, dummy1, dummy2, topLevel, l);
     1390  return result;
     1391}
     1392
     1393CanonicalForm
     1394GCD_small_p (const CanonicalForm& F, const CanonicalForm&  G,
     1395             CanonicalForm& coF, CanonicalForm& coG,
     1396             bool& topLevel, CFList& l)
    11561397{
    11571398  CanonicalForm A= F;
    11581399  CanonicalForm B= G;
    1159   if (F.isZero() && degree(G) > 0) return G/Lc(G);
    1160   else if (G.isZero() && degree (F) > 0) return F/Lc(F);
    1161   else if (F.isZero() && G.isZero()) return F.genOne();
    1162   if (F.inBaseDomain() || G.inBaseDomain()) return F.genOne();
    1163   if (F.isUnivariate() && fdivides(F, G)) return F/Lc(F);
    1164   if (G.isUnivariate() && fdivides(G, F)) return G/Lc(G);
    1165   if (F == G) return F/Lc(F);
    1166 
     1400  if (F.isZero() && degree(G) > 0)
     1401  {
     1402    coF= 0;
     1403    coG= Lc (G);
     1404    return G/Lc(G);
     1405  }
     1406  else if (G.isZero() && degree (F) > 0)
     1407  {
     1408    coF= Lc (F);
     1409    coG= 0;
     1410    return F/Lc(F);
     1411  }
     1412  else if (F.isZero() && G.isZero())
     1413  {
     1414    coF= coG= 0;
     1415    return F.genOne();
     1416  }
     1417  if (F.inBaseDomain() || G.inBaseDomain())
     1418  {
     1419    coF= F;
     1420    coG= G;
     1421    return F.genOne();
     1422  }
     1423  if (F.isUnivariate() && fdivides(F, G, coG))
     1424  {
     1425    coF= Lc (F);
     1426    return F/Lc(F);
     1427  }
     1428  if (G.isUnivariate() && fdivides(G, F, coF))
     1429  {
     1430    coG= Lc (G);
     1431    return G/Lc(G);
     1432  }
     1433  if (F == G)
     1434  {
     1435    coF= coG= Lc (F);
     1436    return F/Lc(F);
     1437  }
    11671438  CFMap M,N;
    11681439  int best_level= myCompress (A, B, M, N, topLevel);
    11691440
    1170   if (best_level == 0) return B.genOne();
     1441  if (best_level == 0)
     1442  {
     1443    coF= F;
     1444    coG= G;
     1445    return B.genOne();
     1446  }
    11711447
    11721448  A= M(A);
     
    11771453  //univariate case
    11781454  if (A.isUnivariate() && B.isUnivariate())
    1179     return N (gcd (A, B));
    1180 
    1181   int substitute= substituteCheck (A, B);
    1182 
    1183   if (substitute > 1)
    1184     subst (A, B, A, B, substitute);
     1455  {
     1456    CanonicalForm result= gcd (A, B);
     1457    coF= N (A/result);
     1458    coG= N (B/result);
     1459    return N (result);
     1460  }
    11851461
    11861462  CanonicalForm cA, cB;    // content of A and B
     
    12041480  }
    12051481
     1482  int sizeNewtonPolyg;
     1483  int ** newtonPolyg= NULL;
     1484  mat_ZZ MM;
     1485  vec_ZZ V;
     1486  bool compressConvexDense= (ppA.level() == 2 && ppB.level() == 2);
     1487  if (compressConvexDense)
     1488  {
     1489    CanonicalForm bufcA= cA;
     1490    CanonicalForm bufcB= cB;
     1491    cA= content (ppA, 1);
     1492    cB= content (ppB, 1);
     1493    ppA /= cA;
     1494    ppB /= cB;
     1495    gcdcAcB *= gcd (cA, cB);
     1496    cA *= bufcA;
     1497    cB *= bufcB;
     1498    if (ppA.isUnivariate() || ppB.isUnivariate())
     1499    {
     1500      if (ppA.level() == ppB.level())
     1501      {
     1502        CanonicalForm result= gcd (ppA, ppB);
     1503        coF= N ((ppA/result)*(cA/gcdcAcB));
     1504        coG= N ((ppB/result)*(cB/gcdcAcB));
     1505        return N (result*gcdcAcB);
     1506      }
     1507      else
     1508      {
     1509        coF= N (ppA*(cA/gcdcAcB));
     1510        coG= N (ppB*(cB/gcdcAcB));
     1511        return N (gcdcAcB);
     1512      }
     1513    }
     1514
     1515    newtonPolyg= newtonPolygon (ppA,ppB, sizeNewtonPolyg);
     1516    convexDense (newtonPolyg, sizeNewtonPolyg, MM, V);
     1517
     1518    for (int i= 0; i < sizeNewtonPolyg; i++)
     1519      delete [] newtonPolyg[i];
     1520    delete [] newtonPolyg;
     1521
     1522    ppA= compress (ppA, MM, V, false);
     1523    ppB= compress (ppB, MM, V, false);
     1524    MM= inv (MM);
     1525
     1526    if (ppA.isUnivariate() && ppB.isUnivariate())
     1527    {
     1528      if (ppA.level() == ppB.level())
     1529      {
     1530        CanonicalForm result= gcd (ppA, ppB);
     1531        coF= N (decompress ((ppA/result), MM, V)*(cA/gcdcAcB));
     1532        coG= N (decompress ((ppB/result), MM, V)*(cB/gcdcAcB));
     1533        return N (decompress (result, MM, V)*gcdcAcB);
     1534      }
     1535      else
     1536      {
     1537        coF= N (decompress (ppA, MM, V));
     1538        coG= N (decompress (ppB, MM, V));
     1539        return N (gcdcAcB);
     1540      }
     1541    }
     1542  }
     1543
    12061544  CanonicalForm lcA, lcB;  // leading coefficients of A and B
    12071545  CanonicalForm gcdlcAlcB;
     
    12091547  lcB= uni_lcoeff (ppB);
    12101548
    1211   if (fdivides (lcA, lcB))
     1549  /*if (fdivides (lcA, lcB))
    12121550  {
    12131551    if (fdivides (A, B))
     
    12181556    if (fdivides (B, A))
    12191557      return G/Lc(G);
    1220   }
     1558  }*/
    12211559
    12221560  gcdlcAlcB= gcd (lcA, lcB);
     
    12271565  if (d == 0)
    12281566  {
    1229     if (substitute > 1)
    1230       return N (reverseSubst (gcdcAcB, substitute));
    1231     else
    1232       return N(gcdcAcB);
    1233   }
     1567    coF= N (ppA*(cA/gcdcAcB));
     1568    coG= N (ppB*(cB/gcdcAcB));
     1569    return N(gcdcAcB);
     1570  }
     1571
    12341572  d0= totaldegree (ppB, Variable (2), Variable (ppB.level()));
    12351573
     
    12391577  if (d == 0)
    12401578  {
    1241     if (substitute > 1)
    1242       return N (reverseSubst (gcdcAcB, substitute));
    1243     else
    1244       return N(gcdcAcB);
     1579    coF= N (ppA*(cA/gcdcAcB));
     1580    coG= N (ppB*(cB/gcdcAcB));
     1581    return N(gcdcAcB);
    12451582  }
    12461583
    12471584  CanonicalForm m, random_element, G_m, G_random_element, H, cH, ppH;
    1248   CanonicalForm newtonPoly= 1;
     1585  CanonicalForm newtonPoly, coF_random_element, coG_random_element,
     1586                coF_m, coG_m, ppCoF, ppCoG;
     1587
     1588  newtonPoly= 1;
    12491589  m= gcdlcAlcB;
    12501590  H= 0;
     1591  coF= 0;
     1592  coG= 0;
    12511593  G_m= 0;
    12521594  Variable alpha, V_buf;
     
    12541596  bool inextension= false;
    12551597  bool inextensionextension= false;
    1256   topLevel= false;
     1598  bool topLevel2= false;
    12571599  CFList source, dest;
     1600  int bound1= degree (ppA, 1);
     1601  int bound2= degree (ppB, 1);
    12581602  do
    12591603  {
    12601604    if (inextension)
    1261       random_element= randomElement (m, V_buf, l, fail);
     1605      random_element= randomElement (m*lcA*lcB, V_buf, l, fail);
    12621606    else
    1263       random_element= FpRandomElement (m, l, fail);
     1607      random_element= FpRandomElement (m*lcA*lcB, l, fail);
    12641608
    12651609    if (!fail && !inextension)
     
    12681612      TIMING_START (gcd_recursion);
    12691613      G_random_element=
    1270       GCD_small_p (ppA (random_element,x), ppB (random_element,x), topLevel,
    1271       list);
     1614      GCD_small_p (ppA (random_element,x), ppB (random_element,x),
     1615                   coF_random_element, coG_random_element, topLevel2,
     1616                   list);
    12721617      TIMING_END_AND_PRINT (gcd_recursion,
    12731618                            "time for recursive call: ");
     
    12791624      TIMING_START (gcd_recursion);
    12801625      G_random_element=
    1281       GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x), alpha,
    1282                         list, topLevel);
     1626      GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x),
     1627                        coF_random_element, coG_random_element, alpha,
     1628                        list, topLevel2);
    12831629      TIMING_END_AND_PRINT (gcd_recursion,
    12841630                            "time for recursive call: ");
     
    12971643        inextension= true;
    12981644        fail= false;
    1299         random_element= randomElement (m, alpha, l, fail);
     1645        random_element= randomElement (m*lcA*lcB, alpha, l, fail);
    13001646        deg++;
    13011647      } while (fail);
     
    13041650      TIMING_START (gcd_recursion);
    13051651      G_random_element=
    1306       GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x), alpha,
    1307                         list, topLevel);
     1652      GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x),
     1653                        coF_random_element, coG_random_element, alpha,
     1654                        list, topLevel2);
    13081655      TIMING_END_AND_PRINT (gcd_recursion,
    13091656                            "time for recursive call: ");
     
    13251672      {
    13261673        m= mapDown (m, prim_elem, im_prim_elem, alpha, source, dest);
    1327         G_m= mapDown (m, prim_elem, im_prim_elem, alpha, source, dest);
     1674        G_m= mapDown (G_m, prim_elem, im_prim_elem, alpha, source, dest);
     1675        coF_m= mapDown (coF_m, prim_elem, im_prim_elem, alpha, source, dest);
     1676        coG_m= mapDown (coG_m, prim_elem, im_prim_elem, alpha, source, dest);
    13281677        newtonPoly= mapDown (newtonPoly, prim_elem, im_prim_elem, alpha,
    13291678                             source, dest);
     
    13321681        gcdlcAlcB= mapDown (gcdlcAlcB, prim_elem, im_prim_elem, alpha, source,
    13331682                            dest);
     1683        lcA= mapDown (lcA, prim_elem, im_prim_elem, alpha, source, dest);
     1684        lcB= mapDown (lcB, prim_elem, im_prim_elem, alpha, source, dest);
    13341685        for (CFListIterator i= l; i.hasItem(); i++)
    13351686          i.getItem()= mapDown (i.getItem(), prim_elem, im_prim_elem, alpha,
     
    13521703      m= mapUp (m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
    13531704      G_m= mapUp (G_m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
     1705      coF_m= mapUp (coF_m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
     1706      coG_m= mapUp (coG_m, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
    13541707      newtonPoly= mapUp (newtonPoly, alpha, V_buf, prim_elem, im_prim_elem,
    13551708                          source, dest);
     
    13581711      gcdlcAlcB= mapUp (gcdlcAlcB, alpha, V_buf, prim_elem, im_prim_elem,
    13591712                         source, dest);
     1713      lcA= mapUp (lcA, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
     1714      lcB= mapUp (lcB, alpha, V_buf, prim_elem, im_prim_elem, source, dest);
    13601715      fail= false;
    1361       random_element= randomElement (m, V_buf, l, fail );
     1716      random_element= randomElement (m*lcA*lcB, V_buf, l, fail );
    13621717      DEBOUTLN (cerr, "fail= " << fail);
    13631718      CFList list;
    13641719      TIMING_START (gcd_recursion);
    13651720      G_random_element=
    1366       GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x), V_buf,
    1367                         list, topLevel);
     1721      GCD_Fp_extension (ppA (random_element, x), ppB (random_element, x),
     1722                        coF_random_element, coG_random_element, V_buf,
     1723                        list, topLevel2);
    13681724      TIMING_END_AND_PRINT (gcd_recursion,
    13691725                            "time for recursive call: ");
     
    13791735    if (d0 == 0)
    13801736    {
    1381       if (substitute > 1)
    1382         return N (reverseSubst (gcdcAcB, substitute));
    1383       else
    1384         return N(gcdcAcB);
    1385     }
     1737      coF= N (ppA*(cA/gcdcAcB));
     1738      coG= N (ppB*(cB/gcdcAcB));
     1739      return N(gcdcAcB);
     1740    }
     1741
    13861742    if (d0 >  d)
    13871743    {
     
    13941750                       *G_random_element;
    13951751
     1752    coF_random_element= (lcA(random_element,x)/uni_lcoeff(coF_random_element))
     1753                        *coF_random_element;
     1754    coG_random_element= (lcB(random_element,x)/uni_lcoeff(coG_random_element))
     1755                        *coG_random_element;
    13961756
    13971757    if (!G_random_element.inCoeffDomain())
     
    14071767      G_m= 0;
    14081768      d= d0;
     1769      coF_m= 0;
     1770      coG_m= 0;
    14091771    }
    14101772
    14111773    TIMING_START (newton_interpolation);
    14121774    H= newtonInterp (random_element, G_random_element, newtonPoly, G_m, x);
     1775    coF= newtonInterp (random_element, coF_random_element, newtonPoly, coF_m,x);
     1776    coG= newtonInterp (random_element, coG_random_element, newtonPoly, coG_m,x);
    14131777    TIMING_END_AND_PRINT (newton_interpolation,
    14141778                          "time for newton_interpolation: ");
    14151779
    14161780    //termination test
    1417     if (uni_lcoeff (H) == gcdlcAlcB)
    1418     {
    1419       cH= uni_content (H);
     1781    if ((uni_lcoeff (H) == gcdlcAlcB) || (G_m == H))
     1782    {
     1783      if (gcdlcAlcB.isOne())
     1784        cH= 1;
     1785      else
     1786        cH= uni_content (H);
    14201787      ppH= H/cH;
    14211788      ppH /= Lc (ppH);
     1789      CanonicalForm lcppH= gcdlcAlcB/cH;
     1790      CanonicalForm ccoF= lcppH/Lc (lcppH);
     1791      CanonicalForm ccoG= lcppH/Lc (lcppH);
     1792      ppCoF= coF/ccoF;
     1793      ppCoG= coG/ccoG;
    14221794      DEBOUTLN (cerr, "ppH= " << ppH);
    1423       if (fdivides (ppH, A) && fdivides (ppH, B))
    1424       {
    1425         if (substitute > 1)
    1426         {
    1427           ppH= reverseSubst (ppH, substitute);
    1428           gcdcAcB= reverseSubst (gcdcAcB, substitute);
     1795      if (((degree (ppCoF,1)+degree (ppH,1) == bound1) &&
     1796           (degree (ppCoG,1)+degree (ppH,1) == bound2) &&
     1797           terminationTest (ppA, ppB, ppCoF, ppCoG, ppH)) ||
     1798           (fdivides (ppH, ppA, ppCoF) && fdivides (ppH, ppB, ppCoG)))
     1799      {
     1800        if (compressConvexDense)
     1801        {
     1802          ppH= decompress (ppH, MM, V);
     1803          ppCoF= decompress (ppCoF, MM, V);
     1804          ppCoG= decompress (ppCoG, MM, V);
    14291805        }
     1806        coF= N ((cA/gcdcAcB)*ppCoF);
     1807        coG= N ((cB/gcdcAcB)*ppCoG);
    14301808        return N(gcdcAcB*ppH);
    14311809      }
     
    14331811
    14341812    G_m= H;
     1813    coF_m= coF;
     1814    coG_m= coG;
    14351815    newtonPoly= newtonPoly*(x - random_element);
    14361816    m= m*(x - random_element);
     
    28553235    return N (gcd (A, B));
    28563236
    2857   int substitute= substituteCheck (A, B);
    2858 
    2859   if (substitute > 1)
    2860     subst (A, B, A, B, substitute);
    2861 
    28623237  CanonicalForm cA, cB;    // content of A and B
    28633238  CanonicalForm ppA, ppB;    // primitive part of A and B
     
    29013276
    29023277  if (d == 0)
    2903   {
    2904     if (substitute > 1)
    2905       return N(reverseSubst (gcdcAcB, substitute));
    2906     else
    2907       return N(gcdcAcB);
    2908   }
     3278    return N(gcdcAcB);
    29093279  d0= totaldegree (ppB, Variable (2), Variable (ppB.level()));
    29103280
     
    29133283
    29143284  if (d == 0)
    2915   {
    2916     if (substitute > 1)
    2917       return N(reverseSubst (gcdcAcB, substitute));
    2918     else
    2919       return N(gcdcAcB);
    2920   }
     3285    return N(gcdcAcB);
    29213286
    29223287  CanonicalForm m, random_element, G_m, G_random_element, H, cH, ppH, skeleton;
     
    30183383
    30193384    if (d0 == 0)
    3020     {
    3021       if (substitute > 1)
    3022         return N(reverseSubst (gcdcAcB, substitute));
    3023       else
    3024         return N(gcdcAcB);
    3025     }
     3385      return N(gcdcAcB);
    30263386    if (d0 >  d)
    30273387    {
     
    30603420        //maybe it's better to test if ppH is an element of F(\alpha) before
    30613421        //mapping down
    3062         DEBOUTLN (cerr, "ppH before mapDown= " << ppH);
    3063         ppH= mapDown (ppH, prim_elem, im_prim_elem, alpha, u, v);
    3064         ppH /= Lc(ppH);
    3065         DEBOUTLN (cerr, "ppH after mapDown= " << ppH);
    3066         if (fdivides (ppH, A) && fdivides (ppH, B))
    3067         {
    3068           if (substitute > 1)
    3069           {
    3070             ppH= reverseSubst (ppH, substitute);
    3071             gcdcAcB= reverseSubst (gcdcAcB, substitute);
    3072           }
     3422        if (fdivides (ppH, ppA) && fdivides (ppH, ppB))
     3423        {
     3424          DEBOUTLN (cerr, "ppH before mapDown= " << ppH);
     3425          ppH= mapDown (ppH, prim_elem, im_prim_elem, alpha, u, v);
     3426          ppH /= Lc(ppH);
     3427          DEBOUTLN (cerr, "ppH after mapDown= " << ppH);
    30733428          return N(gcdcAcB*ppH);
    30743429        }
    30753430      }
    3076       else if (fdivides (ppH, A) && fdivides (ppH, B))
    3077       {
    3078         if (substitute > 1)
    3079         {
    3080           ppH= reverseSubst (ppH, substitute);
    3081           gcdcAcB= reverseSubst (gcdcAcB, substitute);
    3082         }
     3431      else if (fdivides (ppH, ppA) && fdivides (ppH, ppB))
    30833432        return N(gcdcAcB*ppH);
    3084       }
    30853433    }
    30863434    G_m= H;
     
    32043552
    32053553        if (d0 == 0)
    3206         {
    3207           if (substitute > 1)
    3208             return N(reverseSubst (gcdcAcB, substitute));
    3209           else
    3210             return N(gcdcAcB);
    3211         }
     3554          return N(gcdcAcB);
    32123555        if (d0 >  d)
    32133556        {
     
    32503593            //maybe it's better to test if ppH is an element of F(\alpha) before
    32513594            //mapping down
    3252             DEBOUTLN (cerr, "ppH before mapDown= " << ppH);
    3253             ppH= mapDown (ppH, prim_elem, im_prim_elem, alpha, u, v);
    3254             ppH /= Lc(ppH);
    3255             DEBOUTLN (cerr, "ppH after mapDown= " << ppH);
    3256             if (fdivides (ppH, A) && fdivides (ppH, B))
     3595            if (fdivides (ppH, ppA) && fdivides (ppH, ppB))
    32573596            {
    3258               if (substitute > 1)
    3259               {
    3260                 ppH= reverseSubst (ppH, substitute);
    3261                 gcdcAcB= reverseSubst (gcdcAcB, substitute);
    3262               }
     3597              DEBOUTLN (cerr, "ppH before mapDown= " << ppH);
     3598              ppH= mapDown (ppH, prim_elem, im_prim_elem, alpha, u, v);
     3599              ppH /= Lc(ppH);
     3600              DEBOUTLN (cerr, "ppH after mapDown= " << ppH);
    32633601              return N(gcdcAcB*ppH);
    32643602            }
    32653603          }
    3266           else if (fdivides (ppH, A) && fdivides (ppH, B))
     3604          else if (fdivides (ppH, ppA) && fdivides (ppH, ppB))
    32673605          {
    3268             if (substitute > 1)
    3269             {
    3270               ppH= reverseSubst (ppH, substitute);
    3271               gcdcAcB= reverseSubst (gcdcAcB, substitute);
    3272             }
    32733606            return N(gcdcAcB*ppH);
    32743607          }
     
    33133646    return N (gcd (A, B));
    33143647
    3315   int substitute= substituteCheck (A, B);
    3316 
    3317   if (substitute > 1)
    3318     subst (A, B, A, B, substitute);
    3319 
    33203648  CanonicalForm cA, cB;    // content of A and B
    33213649  CanonicalForm ppA, ppB;    // primitive part of A and B
     
    33593687
    33603688  if (d == 0)
    3361   {
    3362     if (substitute > 1)
    3363       return N(reverseSubst (gcdcAcB, substitute));
    3364     else
    3365       return N(gcdcAcB);
    3366   }
     3689    return N(gcdcAcB);
     3690
    33673691  d0= totaldegree (ppB, Variable (2), Variable (ppB.level()));
    33683692
     
    33713695
    33723696  if (d == 0)
    3373   {
    3374     if (substitute > 1)
    3375       return N(reverseSubst (gcdcAcB, substitute));
    3376     else
    3377       return N(gcdcAcB);
    3378   }
     3697    return N(gcdcAcB);
    33793698
    33803699  CanonicalForm m, random_element, G_m, G_random_element, H, cH, ppH, skeleton;
     
    35193838
    35203839    if (d0 == 0)
    3521     {
    3522       if (substitute > 1)
    3523         return N(reverseSubst (gcdcAcB, substitute));
    3524       else
    3525         return N(gcdcAcB);
    3526     }
     3840      return N(gcdcAcB);
    35273841    if (d0 >  d)
    35283842    {
     
    35613875      DEBOUTLN (cerr, "ppH= " << ppH);
    35623876
    3563       if (fdivides (ppH, A) && fdivides (ppH, B))
    3564       {
    3565         if (substitute > 1)
    3566         {
    3567           ppH= reverseSubst (ppH, substitute);
    3568           gcdcAcB= reverseSubst (gcdcAcB, substitute);
    3569         }
     3877      if (fdivides (ppH, ppA) && fdivides (ppH, ppB))
    35703878        return N(gcdcAcB*ppH);
    3571       }
    35723879    }
    35733880    G_m= H;
     
    37434050
    37444051        if (d0 == 0)
    3745         {
    3746           if (substitute > 1)
    3747             return N(reverseSubst (gcdcAcB, substitute));
    3748           else
    3749             return N(gcdcAcB);
    3750         }
     4052          return N(gcdcAcB);
    37514053        if (d0 >  d)
    37524054        {
     
    37864088          ppH /= Lc (ppH);
    37874089          DEBOUTLN (cerr, "ppH= " << ppH);
    3788           if (fdivides (ppH, A) && fdivides (ppH, B))
    3789           {
    3790             if (substitute > 1)
    3791             {
    3792               ppH= reverseSubst (ppH, substitute);
    3793               gcdcAcB= reverseSubst (gcdcAcB, substitute);
    3794             }
     4090          if (fdivides (ppH, ppA) && fdivides (ppH, ppB))
    37954091            return N(gcdcAcB*ppH);
    3796           }
    37974092        }
    37984093
     
    43554650  }
    43564651
    4357   CanonicalForm cand;
     4652  CanonicalForm cand, contcand;
    43584653  CanonicalForm result;
    43594654  int o, t;
     
    45984893      if (gcdfound == 1)
    45994894      {
    4600         cand = DD[2] / content( DD[2], Variable(1) );
    4601         gcdfound = fdivides( cand, G ) && fdivides ( cand, F );
     4895        contcand= content (DD[2], Variable (1));
     4896        cand = DD[2] / contcand;
     4897        if (B_is_F)
     4898          gcdfound = fdivides( cand, G ) && cand*(DD[1]/(lcD/contcand)) == F;
     4899        else
     4900          gcdfound = fdivides( cand, F ) && cand*(DD[1]/(lcD/contcand)) == G;
    46024901
    46034902        if (passToGF && gcdfound)
  • factory/cf_gcd_smallp.h

    ra03496 re7676a  
    4444                           bool& top_level, CFList& l);
    4545
     46CanonicalForm GCD_small_p (const CanonicalForm& F, const CanonicalForm&  G, CanonicalForm& coF, CanonicalForm& coG,
     47                           bool& topLevel, CFList& l);
     48
    4649///GCD of A and B over \f$ F_{p} \f$
    4750static inline CanonicalForm GCD_small_p (const CanonicalForm& A, const CanonicalForm& B)
     
    5053  bool top_level= true;
    5154  return GCD_small_p (A, B, top_level, list);
     55}
     56
     57static inline CanonicalForm GCD_small_p (const CanonicalForm& A, const CanonicalForm& B, CanonicalForm& coA, CanonicalForm& coB)
     58{
     59  CFList list;
     60  bool top_level= true;
     61  return GCD_small_p (A, B, coA, coB, top_level, list);
    5262}
    5363
     
    102112CFArray
    103113getMonoms (const CanonicalForm& F);
     114
     115bool
     116terminationTest (const CanonicalForm& F, const CanonicalForm& G,
     117                 const CanonicalForm& coF, const CanonicalForm& coG,
     118                 const CanonicalForm& cand);
    104119#endif
  • factory/fac_ezgcd.cc

    ra03496 re7676a  
    1 /* emacs edit mode for this file is -*- C++ -*- */
    2 /* $Id$ */
     1/*****************************************************************************\
     2 * Computer Algebra System SINGULAR
     3\*****************************************************************************/
     4/** @file fac_ezgcd.cc
     5 *
     6 * This file implements the GCD of two multivariate polynomials over Q using
     7 * EZ-GCD as described in "Algorithms for Computer Algebra" by Geddes, Czapor,
     8 * Labahnn
     9 *
     10 * @author Martin Lee
     11 *
     12 **/
     13/*****************************************************************************/
    314
    415#include "config.h"
     
    920#include "cf_defs.h"
    1021#include "canonicalform.h"
    11 #include "fac_util.h"
     22#include "fac_util.h" // HEADER for this file
    1223#include "cf_algorithm.h"
    1324#include "cf_reval.h"
     
    1627#include "fac_distrib.h"
    1728#include "templates/ftmpl_functions.h"
    18 
    19 static void findeval( const CanonicalForm & F, const CanonicalForm & G, CanonicalForm & Fb, CanonicalForm & Gb, CanonicalForm & Db, REvaluation & b, int delta, int degF, int degG );
    20 
    21 static CanonicalForm ezgcd ( const CanonicalForm & FF, const CanonicalForm & GG, REvaluation & b, bool internal );
    22 
    23 static CanonicalForm ezgcd_specialcase ( const CanonicalForm & F, const CanonicalForm & G, REvaluation & b, const modpk & bound );
    24 
    25 static modpk findBound ( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & lcF, const CanonicalForm & lcG, int degF, int degG );
    26 
    27 static modpk enlargeBound ( const CanonicalForm & F, const CanonicalForm & Lb, const CanonicalForm & Db, const modpk & pk );
     29#include "cf_map.h"
     30#include "facHensel.h"
     31
     32static
     33int compress4EZGCD (const CanonicalForm& F, const CanonicalForm& G, CFMap & M,
     34                    CFMap & N, int& both_non_zero)
     35{
     36  int n= tmax (F.level(), G.level());
     37  int * degsf= new int [n + 1];
     38  int * degsg= new int [n + 1];
     39
     40  for (int i = 0; i <= n; i++)
     41    degsf[i]= degsg[i]= 0;
     42
     43  degsf= degrees (F, degsf);
     44  degsg= degrees (G, degsg);
     45
     46  both_non_zero= 0;
     47  int f_zero= 0;
     48  int g_zero= 0;
     49
     50  for (int i= 1; i <= n; i++)
     51  {
     52    if (degsf[i] != 0 && degsg[i] != 0)
     53    {
     54      both_non_zero++;
     55      continue;
     56    }
     57    if (degsf[i] == 0 && degsg[i] != 0 && i <= G.level())
     58    {
     59      f_zero++;
     60      continue;
     61    }
     62    if (degsg[i] == 0 && degsf[i] && i <= F.level())
     63    {
     64      g_zero++;
     65      continue;
     66    }
     67  }
     68
     69  if (both_non_zero == 0)
     70  {
     71    delete [] degsf;
     72    delete [] degsg;
     73    return 0;
     74  }
     75
     76  // map Variables which do not occur in both polynomials to higher levels
     77  int k= 1;
     78  int l= 1;
     79  for (int i= 1; i <= n; i++)
     80  {
     81    if (degsf[i] != 0 && degsg[i] == 0 && i <= F.level())
     82    {
     83      if (k + both_non_zero != i)
     84      {
     85        M.newpair (Variable (i), Variable (k + both_non_zero));
     86        N.newpair (Variable (k + both_non_zero), Variable (i));
     87      }
     88      k++;
     89    }
     90    if (degsf[i] == 0 && degsg[i] != 0 && i <= G.level())
     91    {
     92      if (l + g_zero + both_non_zero != i)
     93      {
     94        M.newpair (Variable (i), Variable (l + g_zero + both_non_zero));
     95        N.newpair (Variable (l + g_zero + both_non_zero), Variable (i));
     96      }
     97      l++;
     98    }
     99  }
     100
     101  // sort Variables x_{i} in decreasing order of
     102  // min(deg_{x_{i}}(f),deg_{x_{i}}(g))
     103  int m= tmin (F.level(), G.level());
     104  int max_min_deg;
     105  k= both_non_zero;
     106  l= 0;
     107  int i= 1;
     108  while (k > 0)
     109  {
     110    max_min_deg= tmin (degsf[i], degsg[i]);
     111    while (max_min_deg == 0)
     112    {
     113      i++;
     114      max_min_deg= tmin (degsf[i], degsg[i]);
     115    }
     116    for (int j= i + 1; j <= m; j++)
     117    {
     118      if ((tmin (degsf[j],degsg[j]) < max_min_deg) &&
     119          (tmin (degsf[j], degsg[j]) != 0))
     120      {
     121        max_min_deg= tmin (degsf[j], degsg[j]);
     122        l= j;
     123      }
     124    }
     125
     126    if (l != 0)
     127    {
     128      if (l != k)
     129      {
     130        M.newpair (Variable (l), Variable(k));
     131        N.newpair (Variable (k), Variable(l));
     132        degsf[l]= 0;
     133        degsg[l]= 0;
     134        l= 0;
     135      }
     136      else
     137      {
     138        degsf[l]= 0;
     139        degsg[l]= 0;
     140        l= 0;
     141      }
     142    }
     143    else if (l == 0)
     144    {
     145      if (i != k)
     146      {
     147        M.newpair (Variable (i), Variable (k));
     148        N.newpair (Variable (k), Variable (i));
     149        degsf[i]= 0;
     150        degsg[i]= 0;
     151      }
     152      else
     153      {
     154        degsf[i]= 0;
     155        degsg[i]= 0;
     156      }
     157      i++;
     158    }
     159    k--;
     160  }
     161
     162  delete [] degsf;
     163  delete [] degsg;
     164
     165  return both_non_zero;
     166}
     167
     168static inline
     169CanonicalForm myShift2Zero (const CanonicalForm& F, CFList& Feval,
     170                            const CFList& evaluation)
     171{
     172  CanonicalForm A= F;
     173  int k= 2;
     174  for (CFListIterator i= evaluation; i.hasItem(); i++, k++)
     175    A= A (Variable (k) + i.getItem(), k);
     176
     177  CanonicalForm buf= A;
     178  Feval= CFList();
     179  Feval.append (buf);
     180  for (k= evaluation.length() + 1; k > 2; k--)
     181  {
     182    buf= mod (buf, Variable (k));
     183    Feval.insert (buf);
     184  }
     185  return A;
     186}
     187
     188static inline
     189CanonicalForm myReverseShift (const CanonicalForm& F, const CFList& evaluation)
     190{
     191  int l= evaluation.length() + 1;
     192  CanonicalForm result= F;
     193  CFListIterator j= evaluation;
     194  for (int i= 2; i < l + 1; i++, j++)
     195  {
     196    if (F.level() < i)
     197      continue;
     198    result= result (Variable (i) - j.getItem(), i);
     199  }
     200  return result;
     201}
     202
     203static inline
     204Evaluation optimize4Lift (const CanonicalForm& F, CFMap & M,
     205                    CFMap & N, const Evaluation& A)
     206{
     207  int n= F.level();
     208  int * degsf= new int [n + 1];
     209
     210  for (int i = 0; i <= n; i++)
     211    degsf[i]= 0;
     212
     213  degsf= degrees (F, degsf);
     214
     215  Evaluation result= Evaluation (A.min(), A.max());
     216  ASSERT (A.min() == 2, "expected A.min() == 2");
     217  ASSERT (A.max() == n, "expected A.max() == n");
     218  int max_deg;
     219  int k= n;
     220  int l= 1;
     221  int i= 2;
     222  int pos= 2;
     223  while (k > 1)
     224  {
     225    max_deg= degsf [i];
     226    while (max_deg == 0)
     227    {
     228      i++;
     229      max_deg= degsf [i];
     230    }
     231    l= i;
     232    for (int j= i + 1; j <=  n; j++)
     233    {
     234      if (degsf[j] > max_deg)
     235      {
     236        max_deg= degsf[j];
     237        l= j;
     238      }
     239    }
     240
     241    if (l <= n)
     242    {
     243      if (l != pos)
     244      {
     245        result.setValue (pos, A [l]);
     246        M.newpair (Variable (l), Variable (pos));
     247        N.newpair (Variable (pos), Variable (l));
     248        degsf[l]= 0;
     249        l= 2;
     250        if (k == 2 && n == 3)
     251        {
     252          result.setValue (l, A [pos]);
     253          M.newpair (Variable (pos), Variable (l));
     254          N.newpair (Variable (l), Variable (pos));
     255          degsf[pos]= 0;
     256        }
     257      }
     258      else
     259      {
     260        result.setValue (l, A [l]);
     261        degsf [l]= 0;
     262      }
     263    }
     264    pos++;
     265    k--;
     266    l= 2;
     267  }
     268
     269  delete [] degsf;
     270
     271  return result;
     272}
     273
     274static inline
     275int Hensel (const CanonicalForm & UU, CFArray & G, const Evaluation & AA,
     276            const CFArray& LeadCoeffs )
     277{
     278  CFList factors;
     279  factors.append (G[1]);
     280  factors.append (G[2]);
     281
     282  CFMap NN, MM;
     283  Evaluation A= optimize4Lift (UU, MM, NN, AA);
     284
     285  CanonicalForm U= MM (UU);
     286  CFArray LCs= CFArray (1,2);
     287  LCs [1]= MM (LeadCoeffs [1]);
     288  LCs [2]= MM (LeadCoeffs [2]);
     289
     290  CFList evaluation;
     291  for (int i= A.min(); i <= A.max(); i++)
     292    evaluation.append (A [i]);
     293  CFList UEval;
     294  CanonicalForm shiftedU= myShift2Zero (U, UEval, evaluation);
     295
     296  if (size (shiftedU)/getNumVars (U) > 500)
     297    return -1;
     298
     299  CFArray shiftedLCs= CFArray (2);
     300  CFList shiftedLCsEval1, shiftedLCsEval2;
     301  shiftedLCs[0]= myShift2Zero (LCs[1], shiftedLCsEval1, evaluation);
     302  shiftedLCs[1]= myShift2Zero (LCs[2], shiftedLCsEval2, evaluation);
     303  factors.insert (1);
     304  int liftBound= degree (UEval.getLast(), 2) + 1;
     305  CFArray Pi;
     306  CFMatrix M= CFMatrix (liftBound, factors.length() - 1);
     307  CFList diophant;
     308  CFArray lcs= CFArray (2);
     309  lcs [0]= shiftedLCsEval1.getFirst();
     310  lcs [1]= shiftedLCsEval2.getFirst();
     311  nonMonicHenselLift12 (UEval.getFirst(), factors, liftBound, Pi, diophant, M,
     312                        lcs, false);
     313
     314  for (CFListIterator i= factors; i.hasItem(); i++)
     315  {
     316    if (!fdivides (i.getItem(), UEval.getFirst()))
     317      return 0;
     318  }
     319
     320  int * liftBounds;
     321  bool noOneToOne= false;
     322  if (U.level() > 2)
     323  {
     324    liftBounds= new int [U.level() - 1]; /* index: 0.. U.level()-2 */
     325    liftBounds[0]= liftBound;
     326    for (int i= 1; i < U.level() - 1; i++)
     327      liftBounds[i]= degree (shiftedU, Variable (i + 2)) + 1;
     328    factors= nonMonicHenselLift2 (UEval, factors, liftBounds, U.level() - 1,
     329                                  false, shiftedLCsEval1, shiftedLCsEval2, Pi,
     330                                  diophant, noOneToOne);
     331    delete [] liftBounds;
     332    if (noOneToOne)
     333      return 0;
     334  }
     335  G[1]= factors.getFirst();
     336  G[2]= factors.getLast();
     337  G[1]= myReverseShift (G[1], evaluation);
     338  G[2]= myReverseShift (G[2], evaluation);
     339  G[1]= NN (G[1]);
     340  G[2]= NN (G[2]);
     341  return 1;
     342}
     343
     344static
     345bool findeval (const CanonicalForm & F, const CanonicalForm & G,
     346               CanonicalForm & Fb, CanonicalForm & Gb, CanonicalForm & Db,
     347               REvaluation & b, int delta, int degF, int degG, int maxeval,
     348               int & count, int& k, int bound, int& l)
     349{
     350  if( count == 0 && delta != 0)
     351  {
     352    if( count++ > maxeval )
     353      return false;
     354  }
     355  if (count > 0)
     356  {
     357    b.nextpoint(k);
     358    if (k == 0)
     359      k++;
     360    l++;
     361    if (l > bound)
     362    {
     363      l= 1;
     364      k++;
     365      if (k > tmax (F.level(), G.level()) - 1)
     366        return false;
     367      b.nextpoint (k);
     368    }
     369    if (count++ > maxeval)
     370      return false;
     371  }
     372  while( true )
     373  {
     374    Fb = b( F );
     375    if( degree( Fb, 1 ) == degF )
     376    {
     377      Gb = b( G );
     378      if( degree( Gb, 1 ) == degG )
     379      {
     380        Db = gcd( Fb, Gb );
     381        if( delta > 0 )
     382        {
     383          if( degree( Db, 1 ) <= delta )
     384            return true;
     385        }
     386        else
     387        {
     388          k++;
     389          return true;
     390        }
     391      }
     392    }
     393    if (k == 0)
     394      k++;
     395    b.nextpoint(k);
     396    l++;
     397    if (l > bound)
     398    {
     399      l= 1;
     400      k++;
     401      if (k > tmax (F.level(), G.level()) - 1)
     402        return false;
     403      b.nextpoint (k);
     404    }
     405    if( count++ > maxeval )
     406      return false;
     407  }
     408}
     409
     410static CanonicalForm
     411ezgcd ( const CanonicalForm & FF, const CanonicalForm & GG, REvaluation & b,
     412        bool internal )
     413{
     414  bool isRat= isOn (SW_RATIONAL);
     415  CanonicalForm F, G, f, g, d, Fb, Gb, Db, Fbt, Gbt, Dbt, B0, B, D0, lcF, lcG,
     416                lcD, cand, contcand, result;
     417  CFArray DD( 1, 2 ), lcDD( 1, 2 );
     418  int degF, degG, delta, t, count, maxeval;
     419  REvaluation bt;
     420  bool gcdfound = false;
     421  Variable x = Variable(1);
     422  count= 0;
     423  maxeval= 200;
     424  int o, l;
     425  o= 0;
     426  l= 1;
     427
     428  if (!isRat)
     429    On (SW_RATIONAL);
     430  F= FF*bCommonDen (FF);
     431  G= GG*bCommonDen (GG);
     432  if (!isRat)
     433    Off (SW_RATIONAL);
     434
     435  CFMap M,N;
     436  int smallestDegLev;
     437  int best_level= compress4EZGCD (F, G, M, N, smallestDegLev);
     438
     439  if (best_level == 0)
     440  {
     441    DEBDECLEVEL( cerr, "ezgcd" );
     442    return G.genOne();
     443  }
     444
     445  F= M (F);
     446  G= M (G);
     447
     448  DEBINCLEVEL( cerr, "ezgcd" );
     449  DEBOUTLN( cerr, "FF = " << FF );
     450  DEBOUTLN( cerr, "GG = " << GG );
     451  f = content( F, x ); g = content( G, x ); d = gcd( f, g );
     452  d /= icontent (d);
     453  DEBOUTLN( cerr, "f = " << f );
     454  DEBOUTLN( cerr, "g = " << g );
     455  F /= f; G /= g;
     456  if ( F.isUnivariate() && G.isUnivariate() )
     457  {
     458    DEBDECLEVEL( cerr, "ezgcd" );
     459    if(F.mvar()==G.mvar())
     460      d*=gcd(F,G);
     461    return N (d);
     462  }
     463
     464  int maxNumVars= tmax (getNumVars (F), getNumVars (G));
     465  int sizeF= size (F);
     466  int sizeG= size (G);
     467
     468
     469  if (!isRat)
     470    On (SW_RATIONAL);
     471  if (sizeF/maxNumVars > 500 && sizeG/maxNumVars > 500)
     472  {
     473    Off(SW_USE_EZGCD);
     474    result=gcd( F, G );
     475    On(SW_USE_EZGCD);
     476    if (!isRat)
     477      Off (SW_RATIONAL);
     478    result /= icontent (result);
     479    DEBDECLEVEL( cerr, "ezgcd" );
     480    return N (d*result);
     481  }
     482
     483  if ( gcd_test_one( F, G, false ) )
     484  {
     485    DEBDECLEVEL( cerr, "ezgcd" );
     486    if (!isRat)
     487      Off (SW_RATIONAL);
     488    return N (d);
     489  }
     490  lcF = LC( F, x ); lcG = LC( G, x );
     491  lcD = gcd( lcF, lcG );
     492  delta = 0;
     493  degF = degree( F, x ); degG = degree( G, x );
     494  t = tmax( F.level(), G.level() );
     495  if ( ! internal )
     496    b = REvaluation( 2, t, IntRandom( 25 ) );
     497  while ( ! gcdfound )
     498  {
     499    /// ---> A2
     500    DEBOUTLN( cerr, "search for evaluation, delta = " << delta );
     501    DEBOUTLN( cerr, "F = " << F );
     502    DEBOUTLN( cerr, "G = " << G );
     503    if (!findeval( F, G, Fb, Gb, Db, b, delta, degF, degG, maxeval, count,
     504                   o, 25, l))
     505    {
     506      Off(SW_USE_EZGCD);
     507      result=gcd( F, G );
     508      On(SW_USE_EZGCD);
     509      if (!isRat)
     510        Off (SW_RATIONAL);
     511      DEBDECLEVEL( cerr, "ezgcd" );
     512      result /= icontent (result);
     513      return N (d*result);
     514    }
     515    DEBOUTLN( cerr, "found evaluation b = " << b );
     516    DEBOUTLN( cerr, "F(b) = " << Fb );
     517    DEBOUTLN( cerr, "G(b) = " << Gb );
     518    DEBOUTLN( cerr, "D(b) = " << Db );
     519    delta = degree( Db );
     520    /// ---> A3
     521    if ( delta == 0 )
     522    {
     523      DEBDECLEVEL( cerr, "ezgcd" );
     524      if (!isRat)
     525        Off (SW_RATIONAL);
     526      return N (d);
     527    }
     528    /// ---> A4
     529    //deltaold = delta;
     530    while ( 1 )
     531    {
     532      bt = b;
     533      if (!findeval( F, G, Fbt, Gbt, Dbt, bt, delta, degF, degG, maxeval, count,
     534                     o, 25,l ))
     535      {
     536        Off(SW_USE_EZGCD);
     537        result=gcd( F, G );
     538        On(SW_USE_EZGCD);
     539        if (!isRat)
     540          Off (SW_RATIONAL);
     541        DEBDECLEVEL( cerr, "ezgcd" );
     542        result /= icontent (result);
     543        return N (d*result);
     544      }
     545      int dd=degree( Dbt );
     546      if ( dd /*degree( Dbt )*/ == 0 )
     547      {
     548        DEBDECLEVEL( cerr, "ezgcd" );
     549        if (!isRat)
     550          Off (SW_RATIONAL);
     551        return N (d);
     552      }
     553      if ( dd /*degree( Dbt )*/ == delta )
     554        break;
     555      else  if ( dd /*degree( Dbt )*/ < delta )
     556      {
     557        delta = dd /*degree( Dbt )*/;
     558        b = bt;
     559        Db = Dbt; Fb = Fbt; Gb = Gbt;
     560      }
     561    }
     562    DEBOUTLN( cerr, "now after A4, delta = " << delta );
     563    /// ---> A5
     564    if (delta == degF)
     565    {
     566      if (degF <= degG  && fdivides (F, G))
     567      {
     568        DEBDECLEVEL( cerr, "ezgcd" );
     569        if (!isRat)
     570          Off (SW_RATIONAL);
     571        return N (d*F);
     572      }
     573      else
     574        delta--;
     575    }
     576    else if (delta == degG)
     577    {
     578      if (degG <= degF && fdivides( G, F ))
     579      {
     580        DEBDECLEVEL( cerr, "ezgcd" );
     581        if (!isRat)
     582          Off (SW_RATIONAL);
     583        return N (d*G);
     584      }
     585      else
     586        delta--;
     587    }
     588    if ( delta != degF && delta != degG )
     589    {
     590      /// ---> A6
     591      bool B_is_F;
     592      CanonicalForm xxx1, xxx2;
     593      CanonicalForm buf;
     594      DD[1] = Fb / Db;
     595      buf= Gb/Db;
     596      xxx1 = gcd( DD[1], Db );
     597      xxx2 = gcd( buf, Db );
     598      if (((xxx1.inCoeffDomain() && xxx2.inCoeffDomain()) &&
     599          (size (F) <= size (G)))
     600            || (xxx1.inCoeffDomain() && !xxx2.inCoeffDomain()))
     601      {
     602        B = F;
     603        DD[2] = Db;
     604        lcDD[1] = lcF;
     605        lcDD[2] = lcD;
     606        B_is_F = true;
     607      }
     608      else if (((xxx1.inCoeffDomain() && xxx2.inCoeffDomain()) &&
     609                (size (G) < size (F)))
     610                || (!xxx1.inCoeffDomain() && xxx2.inCoeffDomain()))
     611      {
     612        DD[1] = buf;
     613        B = G;
     614        DD[2] = Db;
     615        lcDD[1] = lcG;
     616        lcDD[2] = lcD;
     617        B_is_F = false;
     618      }
     619      else
     620      {
     621        //special case
     622        Off(SW_USE_EZGCD);
     623        result=gcd( F, G );
     624        On(SW_USE_EZGCD);
     625        if (!isRat)
     626          Off (SW_RATIONAL);
     627        DEBDECLEVEL( cerr, "ezgcd" );
     628        result /= icontent (result);
     629        return N (d*result);
     630      }
     631      /// ---> A7
     632      DD[2] = DD[2] * ( b( lcDD[2] ) / lc( DD[2] ) );
     633      DD[1] = DD[1] * ( b( lcDD[1] ) / lc( DD[1] ) );
     634      DEBOUTLN( cerr, "(hensel) B    = " << B );
     635      DEBOUTLN( cerr, "(hensel) lcB  = " << LC( B, Variable(1) ) );
     636      DEBOUTLN( cerr, "(hensel) b(B) = " << b(B) );
     637      DEBOUTLN( cerr, "(hensel) DD   = " << DD );
     638      DEBOUTLN( cerr, "(hensel) lcDD = " << lcDD );
     639      gcdfound= Hensel (B*lcD, DD, b, lcDD);
     640      DEBOUTLN( cerr, "(hensel finished) DD   = " << DD );
     641
     642      if (gcdfound == -1)
     643      {
     644        Off (SW_USE_EZGCD);
     645        result= gcd (F,G);
     646        On (SW_USE_EZGCD);
     647        if (!isRat)
     648          Off (SW_RATIONAL);
     649        DEBDECLEVEL( cerr, "ezgcd" );
     650        result /= icontent (result);
     651        return N (d*result);
     652      }
     653
     654      if (gcdfound)
     655      {
     656        contcand= content (DD[2], Variable (1));
     657        cand = DD[2] / contcand;
     658        if (B_is_F)
     659          gcdfound = fdivides( cand, G ) && cand*(DD[1]/(lcD/contcand)) == F;
     660        else
     661          gcdfound = fdivides( cand, F ) && cand*(DD[1]/(lcD/contcand)) == G;
     662      }
     663      /// ---> A8 (gcdfound)
     664    }
     665    delta--;
     666  }
     667  /// ---> A9
     668  DEBDECLEVEL( cerr, "ezgcd" );
     669  cand *= bCommonDen (cand);
     670  if (!isRat)
     671    Off (SW_RATIONAL);
     672  cand /= icontent (cand);
     673  return N (d*cand);
     674}
    28675
    29676CanonicalForm
    30677ezgcd ( const CanonicalForm & FF, const CanonicalForm & GG )
    31678{
    32     REvaluation b;
    33     return ezgcd( FF, GG, b, false );
    34 }
    35 
    36 static CanonicalForm
    37 ezgcd ( const CanonicalForm & FF, const CanonicalForm & GG, REvaluation & b, bool internal )
    38 {
    39     CanonicalForm F, G, f, g, d, Fb, Gb, Db, Fbt, Gbt, Dbt, B0, B, D0, lcF, lcG, lcD;
    40     CFArray DD( 1, 2 ), lcDD( 1, 2 );
    41     int degF, degG, delta, t;
    42     REvaluation bt;
    43     bool gcdfound = false;
    44     Variable x = Variable(1);
    45     modpk bound;
    46 
    47     DEBINCLEVEL( cerr, "ezgcd" );
    48     DEBOUTLN( cerr, "FF = " << FF );
    49     DEBOUTLN( cerr, "GG = " << GG );
    50     f = content( FF, x ); g = content( GG, x ); d = gcd( f, g );
    51     DEBOUTLN( cerr, "f = " << f );
    52     DEBOUTLN( cerr, "g = " << g );
    53     F = FF / f; G = GG / g;
    54     if ( F.isUnivariate() && G.isUnivariate() )
    55     {
    56         DEBDECLEVEL( cerr, "ezgcd" );
    57         if(F.mvar()==G.mvar())
    58           d*=gcd(F,G);
    59         return d;
    60     }
    61     else  if ( gcd_test_one( F, G, false ) )
    62     {
    63         DEBDECLEVEL( cerr, "ezgcd" );
    64         return d;
    65     }
    66     lcF = LC( F, x ); lcG = LC( G, x );
    67     lcD = gcd( lcF, lcG );
    68     delta = 0;
    69     degF = degree( F, x ); degG = degree( G, x );
    70     t = tmax( F.level(), G.level() );
    71     bound = findBound( F, G, lcF, lcG, degF, degG );
    72     if ( ! internal )
    73         b = REvaluation( 2, t, IntRandom( 25 ) );
    74     while ( ! gcdfound ) {
    75         /// ---> A2
    76         DEBOUTLN( cerr, "search for evaluation, delta = " << delta );
    77         DEBOUTLN( cerr, "F = " << F );
    78         DEBOUTLN( cerr, "G = " << G );
    79         findeval( F, G, Fb, Gb, Db, b, delta, degF, degG );
    80         DEBOUTLN( cerr, "found evaluation b = " << b );
    81         DEBOUTLN( cerr, "F(b) = " << Fb );
    82         DEBOUTLN( cerr, "G(b) = " << Gb );
    83         DEBOUTLN( cerr, "D(b) = " << Db );
    84         delta = degree( Db );
    85         /// ---> A3
    86         if ( delta == 0 )
    87         {
    88           DEBDECLEVEL( cerr, "ezgcd" );
    89           return d;
    90         }
    91         /// ---> A4
    92         //deltaold = delta;
    93         while ( 1 ) {
    94             bt = b;
    95             findeval( F, G, Fbt, Gbt, Dbt, bt, delta + 1, degF, degG );
    96             int dd=degree( Dbt );
    97             if ( dd /*degree( Dbt )*/ == 0 )
    98             {
    99                 DEBDECLEVEL( cerr, "ezgcd" );
    100                 return d;
    101             }
    102             if ( dd /*degree( Dbt )*/ == delta )
    103                 break;
    104             else  if ( dd /*degree( Dbt )*/ < delta ) {
    105                 delta = dd /*degree( Dbt )*/;
    106                 b = bt;
    107                 Db = Dbt; Fb = Fbt; Gb = Gbt;
    108             }
    109         }
    110         DEBOUTLN( cerr, "now after A4, delta = " << delta );
    111         /// ---> A5
    112         if ( degF <= degG && delta == degF && fdivides( F, G ) )
    113         {
    114             DEBDECLEVEL( cerr, "ezgcd" );
    115             return d*F;
    116         }
    117         if ( degG < degF && delta == degG && fdivides( G, F ) )
    118         {
    119             DEBDECLEVEL( cerr, "ezgcd" );
    120             return d*G;
    121         }
    122         if ( delta != degF && delta != degG ) {
    123             bool B_is_F;
    124             /// ---> A6
    125             CanonicalForm xxx;
    126             //if ( gcd( (DD[1] = Fb / Db), Db ) == 1 ) {
    127             DD[1] = Fb / Db;
    128             xxx= gcd( DD[1], Db );
    129             DEBOUTLN( cerr, "gcd((Fb/Db),Db) = " << xxx );
    130             DEBOUTLN( cerr, "Fb/Db = " << DD[1] );
    131             DEBOUTLN( cerr, "Db = " << Db );
    132             if (xxx.inCoeffDomain()) {
    133                 B = F;
    134                 DD[2] = Db;
    135                 lcDD[1] = lcF;
    136                 lcDD[2] = lcF;
    137                 B *= lcF;
    138                 B_is_F=true;
    139             }
    140             //else  if ( gcd( (DD[1] = Gb / Db), Db ) == 1 ) {
    141             else
    142             {
    143               DD[1] = Gb / Db;
    144               xxx=gcd( DD[1], Db );
    145               DEBOUTLN( cerr, "gcd((Gb/Db),Db) = " << xxx );
    146               DEBOUTLN( cerr, "Gb/Db = " << DD[1] );
    147               DEBOUTLN( cerr, "Db = " << Db );
    148               if (xxx.inCoeffDomain())
    149               {
    150                 B = G;
    151                 DD[2] = Db;
    152                 lcDD[1] = lcG;
    153                 lcDD[2] = lcG;
    154                 B *= lcG;
    155                 B_is_F=false;
    156               }
    157               else
    158               {
    159 #ifdef DEBUGOUTPUT
    160                 CanonicalForm dummyres = d * ezgcd_specialcase( F, G, b, bound );
    161                 DEBDECLEVEL( cerr, "ezgcd" );
    162                 return dummyres;
    163 #else
    164                 return d * ezgcd_specialcase( F, G, b, bound );
    165 #endif
    166               }
    167             }
    168             /// ---> A7
    169             DD[2] = DD[2] * ( b( lcDD[2] ) / lc( DD[2] ) );
    170             DD[1] = DD[1] * ( b( lcDD[1] ) / lc( DD[1] ) );
    171             bound = enlargeBound( B, DD[2], DD[1], bound );
    172             DEBOUTLN( cerr, "(hensel) B    = " << B );
    173             DEBOUTLN( cerr, "(hensel) lcB  = " << LC( B, Variable(1) ) );
    174             DEBOUTLN( cerr, "(hensel) b(B) = " << b(B) );
    175             DEBOUTLN( cerr, "(hensel) DD   = " << DD );
    176             DEBOUTLN( cerr, "(hensel) lcDD = " << lcDD );
    177             gcdfound = Hensel( B, DD, lcDD, b, bound, x );
    178             DEBOUTLN( cerr, "(hensel finished) DD   = " << DD );
    179 
    180             if (gcdfound)
    181             {
    182               CanonicalForm xxx=content(DD[2],Variable(1));
    183               CanonicalForm cand=DD[2] / xxx; //content(DD[2],Variable(1));
    184 #if 0
    185               gcdfound= fdivides(cand,G) &&  fdivides(cand,F);
    186 #else
    187               if (B_is_F /*B==F*lcF*/)
    188               {
    189                 DEBOUTLN( cerr, "(test) G: "<<G<<" % gcd:"<<cand<<" -> " << G%cand );
    190                 gcdfound= fdivides(cand,G);
    191               }
    192               else
    193               {
    194                 DEBOUTLN( cerr, "(test) F: "<<F<<" % gcd:"<<cand<<" -> " << F%cand);
    195                 gcdfound= fdivides(cand,F);
    196               }
    197 #endif
    198             }
    199             /// ---> A8 (gcdfound)
    200         }
    201         delta++;
    202     }
    203     /// ---> A9
    204     DEBDECLEVEL( cerr, "ezgcd" );
    205     return d * DD[2] / content(DD[2],Variable(1));
    206 }
    207 
    208 static CanonicalForm
    209 ezgcd_specialcase ( const CanonicalForm & F, const CanonicalForm & G, REvaluation & /*b*/, const modpk & /*bound*/ )
    210 {
    211     CanonicalForm d;
    212 #if 1
    213     Off(SW_USE_EZGCD);
    214     //bool ntl0=isOn(SW_USE_NTL_GCD_0);
    215     //Off(SW_USE_NTL_GCD_0);
    216     //bool ntlp=isOn(SW_USE_NTL_GCD_P);
    217     //Off(SW_USE_NTL_GCD_P);
    218     d=gcd( F, G );
    219     //if (ntl0) On(SW_USE_NTL_GCD_0);
    220     //if (ntlp) On(SW_USE_NTL_GCD_P);
    221     On(SW_USE_EZGCD);
    222     return d;
    223 #else
    224     /*
    225      * I am not sure, if these lines are much of use.
    226      * Remove?
    227      */
    228     DEBOUTLN( cerr, "ezgcd: special case" );
    229     CanonicalForm Ft, Gt, L, LL, Fb, Gb, Db, Lb, D, Ds, Dt;
    230     CFArray DD( 1, 2 ), lcDD( 1, 2 );
    231     Variable x = Variable( 1 );
    232     bool gcdfound;
    233 
    234     Dt = 1;
    235     /// ---> S1
    236     DEBOUTLN( cerr, "ezgcdspec: (S1)" );
    237     Ft = ezgcd( F, F.deriv( x ) );
    238     if ( Ft.isOne() )
    239     {
    240         // In this case F is squarefree and we came here by bad chance
    241         // (means: bad evaluation point).  Try again with another
    242         // evaluation point.  Bug fix (?) by JS.  The bad example was
    243         // gcd.debug -ocr /+USE_EZGCD/@12/CB
    244         //     '(16*B^8-208*B^6*C+927*B^4*C^2-1512*B^2*C^3+432*C^4)'
    245         //     '(4*B^7*C^2-50*B^5*C^3+208*B^3*C^4-288*B*C^5)'
    246         b.nextpoint();
    247         return ezgcd( F, G, b, true );
    248     }
    249 
    250     DEBOUTLN( cerr, "ezgcdspec: (S1) done, Ft = " << Ft );
    251     L = F / Ft;
    252     /// ---> S2
    253     DEBOUTLN( cerr, "ezgcdspec: (S2)" );
    254 
    255     L = ezgcd( L, G, b, true );
    256     DEBOUTLN( cerr, "ezgcdspec: (S2) done, Ds = " << Ds );
    257     Gt = G / L;
    258     Ds = L; Dt = L;
    259     Lb = b( L ); Gb = b( Gt ); Fb = b( Ft );
    260     d = gcd( LC( L, x ), gcd( LC( Ft, x ), LC( Gt, x ) ) );
    261     while ( true ) {
    262         /// ---> S3
    263         DEBOUTLN( cerr, "ezgcdspec: (S3)" );
    264         DEBOUTLN( cerr, "ezgcdspec: Fb = " << Fb );
    265         DEBOUTLN( cerr, "ezgcdspec: Gb = " << Gb );
    266         DD[1] = gcd( Lb, gcd( Fb, Gb ) );
    267         /// ---> S4
    268         DEBOUTLN( cerr, "ezgcdspec: (S4)" );
    269         if ( degree( DD[1] ) == 0 )
    270             return Ds;
    271         /// ---> S5
    272         DEBOUTLN( cerr, "ezgcdspec: (S5)" );
    273         DEBOUTLN( cerr, "ezgcdspec: Lb = " << Lb );
    274         DEBOUTLN( cerr, "ezgcdspec: Db = " << DD[1] );
    275         Db = DD[1];
    276         if ( ! (DD[2] = Lb/DD[1]).isOne() ) {
    277             DEBOUTLN( cerr, "ezgcdspec: (S55)" );
    278             lcDD[2] = LC( L, x );
    279             lcDD[1] = d;
    280             DD[1] = ( DD[1] * b( d ) ) / lc( DD[1] );
    281             DD[2] = ( DD[2] * b( lcDD[2] ) ) / lc( DD[2] );
    282             LL = L * d;
    283             modpk newbound = enlargeBound( LL, DD[2], DD[1], bound );
    284             DEBOUTLN( cerr, "ezgcdspec: begin with lift." );
    285             DEBOUTLN( cerr, "ezgcdspec: B     = " << LL );
    286             DEBOUTLN( cerr, "ezgcdspec: DD    = " << DD );
    287             DEBOUTLN( cerr, "ezgcdspec: lcDD  = " << lcDD );
    288             DEBOUTLN( cerr, "ezgcdspec: b     = " << b );
    289             DEBOUTLN( cerr, "ezgcdspec: bound = " << bound.getpk() );
    290             DEBOUTLN( cerr, "ezgcdspec: lc(B) = " << LC( LL, x ) );
    291             DEBOUTLN( cerr, "ezgcdspec: test  = " << b( LL ) - DD[1] * DD[2] );
    292             gcdfound = Hensel( LL, DD, lcDD, b, newbound, x );
    293             ASSERT( gcdfound, "fatal error in algorithm" );
    294             Dt = pp( DD[1] );
    295         }
    296         DEBOUTLN( cerr, "ezgcdspec: (S7)" );
    297         Ds = Ds * Dt;
    298         Fb = Fb / Db;
    299         Gb = Gb / Db;
    300     }
    301     // this point is never reached, but to avoid compiler warnings let's return a value
    302     return 0;
    303 #endif
    304 }
    305 
    306 static void
    307 findeval( const CanonicalForm & F, const CanonicalForm & G, CanonicalForm & Fb, CanonicalForm & Gb, CanonicalForm & Db, REvaluation & b, int delta, int degF, int degG )
    308 {
    309     bool ok;
    310     if ( delta != 0 )
    311         b.nextpoint();
    312     DEBOUTLN( cerr, "ezgcd: (findeval) F = " << F  <<", G="<< G);
    313     DEBOUTLN( cerr, "ezgcd: (findeval) degF = " << degF << ", degG="<<degG );
    314     do {
    315         DEBOUTLN( cerr, "ezgcd: (findeval) b = " << b );
    316         Fb = b( F );
    317         ok = degree( Fb ) == degF;
    318         if ( ok ) {
    319             Gb = b( G );
    320             ok = degree( Gb ) == degG;
    321         }
    322 
    323         if ( ok )
    324         {
    325             Db = gcd( Fb, Gb );
    326             if ( delta > 0 )
    327               ok = degree( Db ) < delta;
    328         }
    329         if ( ! ok )
    330         {
    331             b.nextpoint();
    332         }
    333     } while ( ! ok );
    334 }
    335 
    336 static modpk
    337 enlargeBound ( const CanonicalForm & F, const CanonicalForm & Lb, const CanonicalForm & Db, const modpk & pk )
    338 {
    339     DEBOUTLN( cerr, "ezgcd: (enlarge bound) F      = " << F );
    340     DEBOUTLN( cerr, "ezgcd: (enlarge bound) Lb     = " << Lb );
    341     DEBOUTLN( cerr, "ezgcd: (enlarge bound) Db     = " << Db );
    342     DEBOUTLN( cerr, "ezgcd: (enlarge bound) Lb % p = " << mod( Lb, pk.getp() ) );
    343     DEBOUTLN( cerr, "ezgcd: (enlarge bound) Db % p = " << mod( Db, pk.getp() ) );
    344 
    345     CanonicalForm limit = power( CanonicalForm(2), degree( Db ) ) *
    346         tmax( maxNorm( Lb ), tmax( maxNorm( Db ), maxNorm( F ) ) );
    347     int p = pk.getp();
    348     int k = pk.getk();
    349     CanonicalForm bound = pk.getpk();
    350     while ( bound < limit ) {
    351         k++;
    352         bound *= p;
    353     }
    354     k *= 2;
    355     DEBOUTLN( cerr, "ezgcd: (enlarge bound) newbound = " << power( CanonicalForm( p ), k ) );
    356     return modpk( p, k );
    357 }
    358 
    359 static modpk
    360 findBound ( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & lcF, const CanonicalForm & lcG, int degF, int degG )
    361 {
    362     CanonicalForm limit = power( CanonicalForm(2), tmin( degF, degG ) ) *
    363         gcd( icontent( lcF ), icontent( lcG ) ) * tmin( maxNorm( F ), maxNorm( G ) );
    364     int p, i = 0;
    365     do {
    366         p = cf_getBigPrime( i );
    367         i++;
    368     } while ( mod( lcF, p ).isZero() && mod( lcG, p ).isZero() );
    369     CanonicalForm bound = p;
    370     i = 1;
    371     while ( bound < limit ) {
    372         i++;
    373         bound *= p;
    374     }
    375     return modpk( p, i );
    376 }
     679  REvaluation b;
     680  return ezgcd( FF, GG, b, false );
     681}
     682
Note: See TracChangeset for help on using the changeset viewer.