source: git/factory/algext.cc @ 1e5c50

spielwiese
Last change on this file since 1e5c50 was 1e5c50, checked in by Martin Lee <martinlee84@…>, 11 years ago
chg: faster divisibility test in univariate case in QGCD chg: added newtonDivrem to header
  • Property mode set to 100644
File size: 30.9 KB
RevLine 
[0d5627]1#include "config.h"
[4dfcb1]2
[9c6887]3#ifndef NOSTREAMIO
[4dfcb1]4#ifdef HAVE_CSTDIO
5#include <cstdio>
6#else
[c99b6b]7#include <stdio.h>
[4dfcb1]8#endif
9#ifdef HAVE_IOSTREAM_H
[c99b6b]10#include <iostream.h>
[4dd2c4]11#elif defined(HAVE_IOSTREAM)
[4dfcb1]12#include <iostream>
13#endif
[4dd2c4]14#endif
[c99b6b]15
[517530]16#include "cf_assert.h"
[2a95b2]17#include "timing.h"
[517530]18
[fe2d4c]19#include "templates/ftmpl_functions.h"
[c99b6b]20#include "cf_defs.h"
21#include "canonicalform.h"
22#include "cf_iter.h"
23#include "cf_primes.h"
24#include "cf_algorithm.h"
25#include "algext.h"
[359d742]26#include "cf_map.h"
27#include "cf_generator.h"
[1e5c50]28#include "facMul.h"
[c99b6b]29
[2156ec]30#ifdef HAVE_NTL
31#include "NTLconvert.h"
32#endif
33
[4782bc]34#ifdef HAVE_FLINT
35#include "FLINTconvert.h"
36#endif
37
[2a95b2]38TIMING_DEFINE_PRINT(alg_content_p)
39TIMING_DEFINE_PRINT(alg_content)
40TIMING_DEFINE_PRINT(alg_compress)
41TIMING_DEFINE_PRINT(alg_termination)
42TIMING_DEFINE_PRINT(alg_termination_p)
43TIMING_DEFINE_PRINT(alg_reconstruction)
44TIMING_DEFINE_PRINT(alg_newton_p)
45TIMING_DEFINE_PRINT(alg_recursion_p)
46TIMING_DEFINE_PRINT(alg_gcd_p)
47TIMING_DEFINE_PRINT(alg_euclid_p)
48
[fe2d4c]49/// compressing two polynomials F and G, M is used for compressing,
50/// N to reverse the compression
51static
52int myCompress (const CanonicalForm& F, const CanonicalForm& G, CFMap & M,
53                CFMap & N, bool topLevel)
54{
55  int n= tmax (F.level(), G.level());
56  int * degsf= new int [n + 1];
57  int * degsg= new int [n + 1];
58
59  for (int i = 0; i <= n; i++)
60    degsf[i]= degsg[i]= 0;
61
62  degsf= degrees (F, degsf);
63  degsg= degrees (G, degsg);
64
65  int both_non_zero= 0;
66  int f_zero= 0;
67  int g_zero= 0;
68  int both_zero= 0;
69
70  if (topLevel)
71  {
72    for (int i= 1; i <= n; i++)
73    {
74      if (degsf[i] != 0 && degsg[i] != 0)
75      {
76        both_non_zero++;
77        continue;
78      }
79      if (degsf[i] == 0 && degsg[i] != 0 && i <= G.level())
80      {
81        f_zero++;
82        continue;
83      }
84      if (degsg[i] == 0 && degsf[i] && i <= F.level())
85      {
86        g_zero++;
87        continue;
88      }
89    }
90
91    if (both_non_zero == 0)
92    {
93      delete [] degsf;
94      delete [] degsg;
95      return 0;
96    }
97
98    // map Variables which do not occur in both polynomials to higher levels
99    int k= 1;
100    int l= 1;
101    for (int i= 1; i <= n; i++)
102    {
103      if (degsf[i] != 0 && degsg[i] == 0 && i <= F.level())
104      {
105        if (k + both_non_zero != i)
106        {
107          M.newpair (Variable (i), Variable (k + both_non_zero));
108          N.newpair (Variable (k + both_non_zero), Variable (i));
109        }
110        k++;
111      }
112      if (degsf[i] == 0 && degsg[i] != 0 && i <= G.level())
113      {
114        if (l + g_zero + both_non_zero != i)
115        {
116          M.newpair (Variable (i), Variable (l + g_zero + both_non_zero));
117          N.newpair (Variable (l + g_zero + both_non_zero), Variable (i));
118        }
119        l++;
120      }
121    }
122
123    // sort Variables x_{i} in increasing order of
124    // min(deg_{x_{i}}(f),deg_{x_{i}}(g))
125    int m= tmax (F.level(), G.level());
126    int min_max_deg;
127    k= both_non_zero;
128    l= 0;
129    int i= 1;
130    while (k > 0)
131    {
132      if (degsf [i] != 0 && degsg [i] != 0)
133        min_max_deg= tmax (degsf[i], degsg[i]);
134      else
135        min_max_deg= 0;
136      while (min_max_deg == 0)
137      {
138        i++;
139        min_max_deg= tmax (degsf[i], degsg[i]);
140        if (degsf [i] != 0 && degsg [i] != 0)
141          min_max_deg= tmax (degsf[i], degsg[i]);
142        else
143          min_max_deg= 0;
144      }
145      for (int j= i + 1; j <=  m; j++)
146      {
147        if (tmax (degsf[j],degsg[j]) <= min_max_deg && degsf[j] != 0 && degsg [j] != 0)
148        {
149          min_max_deg= tmax (degsf[j], degsg[j]);
150          l= j;
151        }
152      }
153      if (l != 0)
154      {
155        if (l != k)
156        {
157          M.newpair (Variable (l), Variable(k));
158          N.newpair (Variable (k), Variable(l));
159          degsf[l]= 0;
160          degsg[l]= 0;
161          l= 0;
162        }
163        else
164        {
165          degsf[l]= 0;
166          degsg[l]= 0;
167          l= 0;
168        }
169      }
170      else if (l == 0)
171      {
172        if (i != k)
173        {
174          M.newpair (Variable (i), Variable (k));
175          N.newpair (Variable (k), Variable (i));
176          degsf[i]= 0;
177          degsg[i]= 0;
178        }
179        else
180        {
181          degsf[i]= 0;
182          degsg[i]= 0;
183        }
184        i++;
185      }
186      k--;
187    }
188  }
189  else
190  {
191    //arrange Variables such that no gaps occur
192    for (int i= 1; i <= n; i++)
193    {
194      if (degsf[i] == 0 && degsg[i] == 0)
195      {
196        both_zero++;
197        continue;
198      }
199      else
200      {
201        if (both_zero != 0)
202        {
203          M.newpair (Variable (i), Variable (i - both_zero));
204          N.newpair (Variable (i - both_zero), Variable (i));
205        }
206      }
207    }
208  }
209
210  delete [] degsf;
211  delete [] degsg;
212
213  return 1;
214}
215
[ad8e1b]216void tryInvert( const CanonicalForm & F, const CanonicalForm & M, CanonicalForm & inv, bool & fail )
217{ // F, M are required to be "univariate" polynomials in an algebraic variable
218  // we try to invert F modulo M
219  if(F.inBaseDomain())
220  {
221    if(F.isZero())
222    {
223      fail = true;
224      return;
225    }
226    inv = 1/F;
227    return;
228  }
229  CanonicalForm b;
230  Variable a = M.mvar();
231  Variable x = Variable(1);
232  if(!extgcd( replacevar( F, a, x ), replacevar( M, a, x ), inv, b ).isOne())
233    fail = true;
234  else
235    inv = replacevar( inv, x, a ); // change back to alg var
236}
237
[a8e8b9]238void tryDivrem (const CanonicalForm& F, const CanonicalForm& G, CanonicalForm& Q,
239                CanonicalForm& R, CanonicalForm& inv, const CanonicalForm& mipo,
240                bool& fail)
241{
242  if (F.inCoeffDomain())
243  {
244    Q= 0;
245    R= F;
246    return;
247  }
248
249  CanonicalForm A, B;
250  Variable x= F.mvar();
251  A= F;
252  B= G;
253  int degA= degree (A, x);
254  int degB= degree (B, x);
255
256  if (degA < degB)
257  {
258    R= A;
259    Q= 0;
260    return;
261  }
262
263  tryInvert (Lc (B), mipo, inv, fail);
264  if (fail)
265    return;
266
267  R= A;
268  Q= 0;
269  CanonicalForm Qi;
270  for (int i= degA -degB; i >= 0; i--)
271  {
272    if (degree (R, x) == i + degB)
273    {
274      Qi= Lc (R)*inv*power (x, i);
275      Qi= reduce (Qi, mipo);
276      R -= Qi*B;
277      R= reduce (R, mipo);
278      Q += Qi;
279    }
280  }
281}
282
[ad8e1b]283void tryEuclid( const CanonicalForm & A, const CanonicalForm & B, const CanonicalForm & M, CanonicalForm & result, bool & fail )
[c99b6b]284{
285  CanonicalForm P;
[ad8e1b]286  if(A.inCoeffDomain())
287  {
288    tryInvert( A, M, P, fail );
289    if(fail)
290      return;
291    result = 1;
292    return;
293  }
294  if(B.inCoeffDomain())
295  {
296    tryInvert( B, M, P, fail );
297    if(fail)
298      return;
299    result = 1;
300    return;
301  }
302  // here: both not inCoeffDomain
303  if( A.degree() > B.degree() )
[c99b6b]304  {
305    P = A; result = B;
306  }
307  else
308  {
309    P = B; result = A;
310  }
311  CanonicalForm inv;
312  if( result.isZero() )
313  {
314    tryInvert( Lc(P), M, inv, fail );
315    if(fail)
316      return;
[ad8e1b]317    result = inv*P; // monify result (not reduced, yet)
[5df7d0]318    result= reduce (result, M);
[c99b6b]319    return;
320  }
[ad8e1b]321  Variable x = P.mvar();
[a8e8b9]322  CanonicalForm rem, Q;
[c99b6b]323  // here: degree(P) >= degree(result)
324  while(true)
325  {
[a8e8b9]326    tryDivrem (P, result, Q, rem, inv, M, fail);
327    if (fail)
[c99b6b]328      return;
329    if( rem.isZero() )
330    {
[ad8e1b]331      result *= inv;
[5df7d0]332      result= reduce (result, M);
[c99b6b]333      return;
334    }
[ad8e1b]335    if(result.degree(x) >= rem.degree(x))
336    {
337      P = result;
338      result = rem;
339    }
340    else
341      P = rem;
[359d742]342  }
[c99b6b]343}
344
345bool hasFirstAlgVar( const CanonicalForm & f, Variable & a )
346{
347  if( f.inBaseDomain() ) // f has NO alg. variable
348    return false;
349  if( f.level()<0 ) // f has only alg. vars, so take the first one
350  {
351    a = f.mvar();
352    return true;
353  }
354  for(CFIterator i=f; i.hasTerms(); i++)
355    if( hasFirstAlgVar( i.coeff(), a ))
356      return true; // 'a' is already set
357  return false;
358}
359
[ad8e1b]360CanonicalForm QGCD( const CanonicalForm & F, const CanonicalForm & G );
361int * leadDeg(const CanonicalForm & f, int *degs);
362bool isLess(int *a, int *b, int lower, int upper);
363bool isEqual(int *a, int *b, int lower, int upper);
364CanonicalForm firstLC(const CanonicalForm & f);
365static CanonicalForm trycontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail );
366static CanonicalForm tryvcontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail );
367static CanonicalForm trycf_content ( const CanonicalForm & f, const CanonicalForm & g, const CanonicalForm & M, bool & fail );
[359d742]368
[5df7d0]369static inline CanonicalForm
370tryNewtonInterp (const CanonicalForm alpha, const CanonicalForm u,
371              const CanonicalForm newtonPoly, const CanonicalForm oldInterPoly,
372              const Variable & x, const CanonicalForm& M, bool& fail)
373{
374  CanonicalForm interPoly;
375
376  CanonicalForm inv;
377  tryInvert (newtonPoly (alpha, x), M, inv, fail);
378  if (fail)
379    return 0;
380
381  interPoly= oldInterPoly+reduce ((u - oldInterPoly (alpha, x))*inv*newtonPoly, M);
382  return interPoly;
383}
[359d742]384
[fe2d4c]385void tryBrownGCD( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & M, CanonicalForm & result, bool & fail, bool topLevel )
[ad8e1b]386{ // assume F,G are multivariate polys over Z/p(a) for big prime p, M "univariate" polynomial in an algebraic variable
387  // M is assumed to be monic
[359d742]388  if(F.isZero())
389  {
390    if(G.isZero())
391    {
392      result = G; // G is zero
393      return;
394    }
395    if(G.inCoeffDomain())
396    {
397      tryInvert(G,M,result,fail);
[ad8e1b]398      if(fail)
399        return;
400      result = 1;
[359d742]401      return;
402    }
403    // try to make G monic modulo M
404    CanonicalForm inv;
405    tryInvert(Lc(G),M,inv,fail);
406    if(fail)
407      return;
408    result = inv*G;
[5df7d0]409    result= reduce (result, M);
[359d742]410    return;
411  }
412  if(G.isZero()) // F is non-zero
413  {
414    if(F.inCoeffDomain())
415    {
416      tryInvert(F,M,result,fail);
[ad8e1b]417      if(fail)
418        return;
419      result = 1;
[359d742]420      return;
421    }
422    // try to make F monic modulo M
423    CanonicalForm inv;
424    tryInvert(Lc(F),M,inv,fail);
425    if(fail)
426      return;
427    result = inv*F;
[5df7d0]428    result= reduce (result, M);
[359d742]429    return;
430  }
[ad8e1b]431  // here: F,G both nonzero
[359d742]432  if(F.inCoeffDomain())
433  {
434    tryInvert(F,M,result,fail);
[ad8e1b]435    if(fail)
436      return;
437    result = 1;
[359d742]438    return;
439  }
440  if(G.inCoeffDomain())
441  {
442    tryInvert(G,M,result,fail);
[ad8e1b]443    if(fail)
444      return;
445    result = 1;
[359d742]446    return;
447  }
[2a95b2]448  TIMING_START (alg_compress)
[359d742]449  CFMap MM,NN;
[fe2d4c]450  int lev= myCompress (F, G, MM, NN, topLevel);
451  if (lev == 0)
452  {
453    result= 1;
454    return;
455  }
[359d742]456  CanonicalForm f=MM(F);
457  CanonicalForm g=MM(G);
[2a95b2]458  TIMING_END_AND_PRINT (alg_compress, "time to compress in alg gcd: ")
[ad8e1b]459  // here: f,g are compressed
[359d742]460  // compute largest variable in f or g (least one is Variable(1))
461  int mv = f.level();
462  if(g.level() > mv)
463    mv = g.level();
464  // here: mv is level of the largest variable in f, g
465  if(mv == 1) // f,g univariate
466  {
[2a95b2]467    TIMING_START (alg_euclid_p)
[359d742]468    tryEuclid(f,g,M,result,fail);
[2a95b2]469    TIMING_END_AND_PRINT (alg_euclid_p, "time for euclidean alg mod p: ")
[359d742]470    if(fail)
471      return;
[5df7d0]472    result= NN (reduce (result, M)); // do not forget to map back
[359d742]473    return;
474  }
[2a95b2]475  TIMING_START (alg_content_p)
[359d742]476  // here: mv > 1
[ad8e1b]477  CanonicalForm cf = tryvcontent(f, Variable(2), M, fail); // cf is univariate poly in var(1)
478  if(fail)
479    return;
480  CanonicalForm cg = tryvcontent(g, Variable(2), M, fail);
481  if(fail)
482    return;
[359d742]483  CanonicalForm c;
484  tryEuclid(cf,cg,M,c,fail);
485  if(fail)
486    return;
[ad8e1b]487  // f /= cf
[13f494]488  f.tryDiv (cf, M, fail);
[ad8e1b]489  if(fail)
490    return;
491  // g /= cg
[13f494]492  g.tryDiv (cg, M, fail);
[ad8e1b]493  if(fail)
494    return;
[2a95b2]495  TIMING_END_AND_PRINT (alg_content_p, "time for content in alg gcd mod p: ")
[359d742]496  if(f.inCoeffDomain())
497  {
498    tryInvert(f,M,result,fail);
499    if(fail)
500      return;
[ad8e1b]501    result = NN(c);
[359d742]502    return;
503  }
504  if(g.inCoeffDomain())
505  {
506    tryInvert(g,M,result,fail);
507    if(fail)
508      return;
[ad8e1b]509    result = NN(c);
[359d742]510    return;
511  }
512  int *L = new int[mv+1]; // L is addressed by i from 2 to mv
513  int *N = new int[mv+1];
514  for(int i=2; i<=mv; i++)
515    L[i] = N[i] = 0;
516  L = leadDeg(f, L);
517  N = leadDeg(g, N);
518  CanonicalForm gamma;
[2a95b2]519  TIMING_START (alg_euclid_p)
[359d742]520  tryEuclid( firstLC(f), firstLC(g), M, gamma, fail );
[2a95b2]521  TIMING_END_AND_PRINT (alg_euclid_p, "time for gcd of lcs in alg mod p: ")
[359d742]522  if(fail)
523    return;
[ad8e1b]524  for(int i=2; i<=mv; i++) // entries at i=0,1 not visited
[359d742]525    if(N[i] < L[i])
526      L[i] = N[i];
527  // L is now upper bound for degrees of gcd
528  int *dg_im = new int[mv+1]; // for the degree vector of the image we don't need any entry at i=1
529  for(int i=2; i<=mv; i++)
530    dg_im[i] = 0; // initialize
531  CanonicalForm gamma_image, m=1;
532  CanonicalForm gm=0;
[5df7d0]533  CanonicalForm g_image, alpha, gnew;
[359d742]534  FFGenerator gen = FFGenerator();
[6f08f3]535  Variable x= Variable (1);
[13f494]536  bool divides= true;
[359d742]537  for(FFGenerator gen = FFGenerator(); gen.hasItems(); gen.next())
538  {
539    alpha = gen.item();
[6f08f3]540    gamma_image = reduce(gamma(alpha, x),M); // plug in alpha for var(1)
[359d742]541    if(gamma_image.isZero()) // skip lc-bad points var(1)-alpha
542      continue;
[2a95b2]543    TIMING_START (alg_recursion_p)
[6f08f3]544    tryBrownGCD( f(alpha, x), g(alpha, x), M, g_image, fail, false ); // recursive call with one var less
[2a95b2]545    TIMING_END_AND_PRINT (alg_recursion_p,
546                         "time for recursive calls in alg gcd mod p: ")
[359d742]547    if(fail)
548      return;
[ad8e1b]549    g_image = reduce(g_image, M);
[359d742]550    if(g_image.inCoeffDomain()) // early termination
551    {
552      tryInvert(g_image,M,result,fail);
553      if(fail)
554        return;
555      result = NN(c);
556      return;
557    }
558    for(int i=2; i<=mv; i++)
559      dg_im[i] = 0; // reset (this is necessary, because some entries may not be updated by call to leadDeg)
560    dg_im = leadDeg(g_image, dg_im); // dg_im cannot be NIL-pointer
561    if(isEqual(dg_im, L, 2, mv))
562    {
[5df7d0]563      CanonicalForm inv;
564      tryInvert (firstLC (g_image), M, inv, fail);
565      if (fail)
566        return;
567      g_image *= inv;
[359d742]568      g_image *= gamma_image; // multiply by multiple of image lc(gcd)
[5df7d0]569      g_image= reduce (g_image, M);
[2a95b2]570      TIMING_START (alg_newton_p)
[5df7d0]571      gnew= tryNewtonInterp (alpha, g_image, m, gm, x, M, fail);
[2a95b2]572      TIMING_END_AND_PRINT (alg_newton_p,
573                            "time for Newton interpolation in alg gcd mod p: ")
[359d742]574      // gnew = gm mod m
575      // gnew = g_image mod var(1)-alpha
576      // mnew = m * (var(1)-alpha)
577      if(fail)
578        return;
[5df7d0]579      m *= (x - alpha);
[6bbe94]580      if((firstLC(gnew) == gamma) || (gnew == gm)) // gnew did not change
[359d742]581      {
[2a95b2]582        TIMING_START (alg_termination_p)
[6bbe94]583        cf = tryvcontent(gnew, Variable(2), M, fail);
[ad8e1b]584        if(fail)
585          return;
586        divides = true;
[6bbe94]587        g_image= gnew;
[13f494]588        g_image.tryDiv (cf, M, fail);
[ad8e1b]589        if(fail)
590          return;
[13f494]591        divides= tryFdivides (g_image,f, M, fail); // trial division (f)
[ad8e1b]592        if(fail)
[359d742]593          return;
[ad8e1b]594        if(divides)
595        {
[13f494]596          bool divides2= tryFdivides (g_image,g, M, fail); // trial division (g)
[ad8e1b]597          if(fail)
598            return;
[13f494]599          if(divides2)
[ad8e1b]600          {
[5df7d0]601            result = NN(reduce (c*g_image, M));
[2a95b2]602            TIMING_END_AND_PRINT (alg_termination_p,
603                      "time for successful termination test in alg gcd mod p: ")
[ad8e1b]604            return;
605          }
[359d742]606        }
[2a95b2]607        TIMING_END_AND_PRINT (alg_termination_p,
608                    "time for unsuccessful termination test in alg gcd mod p: ")
[359d742]609      }
610      gm = gnew;
611      continue;
612    }
613
614    if(isLess(L, dg_im, 2, mv)) // dg_im > L --> current point unlucky
615      continue;
616
[ad8e1b]617    // here: isLess(dg_im, L, 2, mv) --> all previous points were unlucky
618    m = CanonicalForm(1); // reset
619    gm = 0; // reset
620    for(int i=2; i<=mv; i++) // tighten bound
621      L[i] = dg_im[i];
[359d742]622  }
623  // we are out of evaluation points
624  fail = true;
625}
626
[2156ec]627static CanonicalForm
628myicontent ( const CanonicalForm & f, const CanonicalForm & c )
629{
[517530]630#ifdef HAVE_NTL
[2156ec]631    if (f.isOne() || c.isOne())
632      return 1;
633    if ( f.inBaseDomain() && c.inBaseDomain())
634    {
635      if (c.isZero()) return abs(f);
636      return bgcd( f, c );
637    }
638    else if ( (f.inCoeffDomain() && c.inCoeffDomain()) ||
639              (f.inCoeffDomain() && c.inBaseDomain()) ||
640              (f.inBaseDomain() && c.inCoeffDomain()))
641    {
642      if (c.isZero()) return abs (f);
[4782bc]643#ifdef HAVE_FLINT
644      fmpz_poly_t FLINTf, FLINTc;
645      convertFacCF2Fmpz_poly_t (FLINTf, f);
646      convertFacCF2Fmpz_poly_t (FLINTc, c);
647      fmpz_poly_gcd (FLINTc, FLINTc, FLINTf);
648      CanonicalForm result;
649      if (f.inCoeffDomain())
650        result= convertFmpz_poly_t2FacCF (FLINTc, f.mvar());
651      else
652        result= convertFmpz_poly_t2FacCF (FLINTc, c.mvar());
653      fmpz_poly_clear (FLINTc);
654      fmpz_poly_clear (FLINTf);
655      return result;
656#else
[2156ec]657      ZZX NTLf= convertFacCF2NTLZZX (f);
658      ZZX NTLc= convertFacCF2NTLZZX (c);
659      NTLc= GCD (NTLc, NTLf);
660      if (f.inCoeffDomain())
661        return convertNTLZZX2CF(NTLc,f.mvar());
662      else
663        return convertNTLZZX2CF(NTLc,c.mvar());
[4782bc]664#endif
[2156ec]665    }
666    else
667    {
668        CanonicalForm g = c;
669        for ( CFIterator i = f; i.hasTerms() && ! g.isOne(); i++ )
670            g = myicontent( i.coeff(), g );
671        return g;
672    }
[517530]673#else
674    return 1;
[2156ec]675#endif
[517530]676}
[2156ec]677
678CanonicalForm
679myicontent ( const CanonicalForm & f )
680{
681#ifdef HAVE_NTL
682    return myicontent( f, 0 );
683#else
684    return 1;
685#endif
686}
687
[ad8e1b]688CanonicalForm QGCD( const CanonicalForm & F, const CanonicalForm & G )
689{ // f,g in Q(a)[x1,...,xn]
690  if(F.isZero())
691  {
692    if(G.isZero())
693      return G; // G is zero
694    if(G.inCoeffDomain())
695      return CanonicalForm(1);
[1682691]696    CanonicalForm lcinv= 1/Lc (G);
697    return G*lcinv; // return monic G
[ad8e1b]698  }
699  if(G.isZero()) // F is non-zero
700  {
701    if(F.inCoeffDomain())
702      return CanonicalForm(1);
[1682691]703    CanonicalForm lcinv= 1/Lc (F);
704    return F*lcinv; // return monic F
[ad8e1b]705  }
706  if(F.inCoeffDomain() || G.inCoeffDomain())
707    return CanonicalForm(1);
708  // here: both NOT inCoeffDomain
709  CanonicalForm f, g, tmp, M, q, D, Dp, cl, newq, mipo;
710  int p, i;
711  int *bound, *other; // degree vectors
712  bool fail;
[713bdb]713  bool off_rational=!isOn(SW_RATIONAL);
[ad8e1b]714  On( SW_RATIONAL ); // needed by bCommonDen
715  f = F * bCommonDen(F);
716  g = G * bCommonDen(G);
[2a95b2]717  TIMING_START (alg_content)
[2156ec]718  CanonicalForm contf= myicontent (f);
719  CanonicalForm contg= myicontent (g);
720  f /= contf;
721  g /= contg;
722  CanonicalForm gcdcfcg= myicontent (contf, contg);
[2a95b2]723  TIMING_END_AND_PRINT (alg_content, "time for content in alg gcd: ")
[ad8e1b]724  Variable a, b;
725  if(hasFirstAlgVar(f,a))
726  {
727    if(hasFirstAlgVar(g,b))
728    {
729      if(b.level() > a.level())
730        a = b;
731    }
732  }
733  else
734  {
735    if(!hasFirstAlgVar(g,a))// both not in extension
736    {
737      Off( SW_RATIONAL );
738      Off( SW_USE_QGCD );
[2156ec]739      tmp = gcdcfcg*gcd( f, g );
[ad8e1b]740      On( SW_USE_QGCD );
[713bdb]741      if (off_rational) Off(SW_RATIONAL);
[ad8e1b]742      return tmp;
743    }
744  }
745  // here: a is the biggest alg. var in f and g AND some of f,g is in extension
746  setReduce(a,false); // do not reduce expressions modulo mipo
747  tmp = getMipo(a);
748  M = tmp * bCommonDen(tmp);
749  // here: f, g in Z[a][x1,...,xn], M in Z[a] not necessarily monic
750  Off( SW_RATIONAL ); // needed by mod
751  // calculate upper bound for degree vector of gcd
752  int mv = f.level(); i = g.level();
753  if(i > mv)
754    mv = i;
755  // here: mv is level of the largest variable in f, g
756  bound = new int[mv+1]; // 'bound' could be indexed from 0 to mv, but we will only use from 1 to mv
757  other = new int[mv+1];
758  for(int i=1; i<=mv; i++) // initialize 'bound', 'other' with zeros
759    bound[i] = other[i] = 0;
760  bound = leadDeg(f,bound); // 'bound' is set the leading degree vector of f
761  other = leadDeg(g,other);
762  for(int i=1; i<=mv; i++) // entry at i=0 not visited
763    if(other[i] < bound[i])
764      bound[i] = other[i];
765  // now 'bound' is the smaller vector
766  cl = lc(M) * lc(f) * lc(g);
767  q = 1;
768  D = 0;
[fe2d4c]769  CanonicalForm test= 0;
770  bool equal= false;
[ad8e1b]771  for( i=cf_getNumBigPrimes()-1; i>-1; i-- )
772  {
773    p = cf_getBigPrime(i);
774    if( mod( cl, p ).isZero() ) // skip lc-bad primes
775      continue;
776    fail = false;
777    setCharacteristic(p);
778    mipo = mapinto(M);
779    mipo /= mipo.lc();
780    // here: mipo is monic
[2a95b2]781    TIMING_START (alg_gcd_p)
[ad8e1b]782    tryBrownGCD( mapinto(f), mapinto(g), mipo, Dp, fail );
[2a95b2]783    TIMING_END_AND_PRINT (alg_gcd_p, "time for alg gcd mod p: ")
[ad8e1b]784    if( fail ) // mipo splits in char p
785      continue;
786    if( Dp.inCoeffDomain() ) // early termination
787    {
788      tryInvert(Dp,mipo,tmp,fail); // check if zero divisor
789      if(fail)
790        continue;
791      setReduce(a,true);
[713bdb]792      if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
[0a7d0ca]793      setCharacteristic(0);
[2156ec]794      return gcdcfcg;
[ad8e1b]795    }
[0a7d0ca]796    setCharacteristic(0);
[ad8e1b]797    // here: Dp NOT inCoeffDomain
798    for(int i=1; i<=mv; i++)
799      other[i] = 0; // reset (this is necessary, because some entries may not be updated by call to leadDeg)
800    other = leadDeg(Dp,other);
[806c18]801
[ad8e1b]802    if(isEqual(bound, other, 1, mv)) // equal
803    {
[6bbe94]804      chineseRemainder( D, q, mapinto(Dp), p, tmp, newq );
[ad8e1b]805      // tmp = Dp mod p
806      // tmp = D mod q
807      // newq = p*q
808      q = newq;
809      if( D != tmp )
810        D = tmp;
811      On( SW_RATIONAL );
[2a95b2]812      TIMING_START (alg_reconstruction)
[6bbe94]813      tmp = Farey( D, q ); // Farey
814      tmp *= bCommonDen (tmp);
[2a95b2]815      TIMING_END_AND_PRINT (alg_reconstruction,
816                            "time for rational reconstruction in alg gcd: ")
[ad8e1b]817      setReduce(a,true); // reduce expressions modulo mipo
818      On( SW_RATIONAL ); // needed by fdivides
[fe2d4c]819      if (test != tmp)
820        test= tmp;
821      else
822        equal= true; // modular image did not add any new information
[2a95b2]823      TIMING_START (alg_termination)
[1e5c50]824#ifdef HAVE_FLINT
825      if (equal && tmp.isUnivariate() && f.isUnivariate() && g.isUnivariate()
826          && f.level() == tmp.level() && tmp.level() == g.level())
827      {
828        CanonicalForm Q, R, sf, sg, stmp;
829        Variable x= Variable (1);
830        sf= swapvar (f, f.mvar(), x);
831        sg= swapvar (g, f.mvar(), x);
832        stmp= swapvar (tmp, f.mvar(), x);
833        newtonDivrem (sf, stmp, Q, R);
834        if (R.isZero())
835        {
836          newtonDivrem (sg, stmp, Q, R);
837          if (R.isZero())
838          {
839            Off (SW_RATIONAL);
840            setReduce (a,true);
841            if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
842            TIMING_END_AND_PRINT (alg_termination,
843                                 "time for successful termination test in alg gcd: ")
844            return tmp*gcdcfcg;
845          }
846        }
847      }
848      else
849#endif
[fe2d4c]850      if(equal && fdivides( tmp, f ) && fdivides( tmp, g )) // trial division
[ad8e1b]851      {
852        Off( SW_RATIONAL );
853        setReduce(a,true);
[713bdb]854        if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
[2a95b2]855        TIMING_END_AND_PRINT (alg_termination,
856                            "time for successful termination test in alg gcd: ")
[2156ec]857        return tmp*gcdcfcg;
[ad8e1b]858      }
[2a95b2]859      TIMING_END_AND_PRINT (alg_termination,
860                          "time for unsuccessful termination test in alg gcd: ")
[ad8e1b]861      Off( SW_RATIONAL );
862      setReduce(a,false); // do not reduce expressions modulo mipo
863      continue;
864    }
865    if( isLess(bound, other, 1, mv) ) // current prime unlucky
866      continue;
867    // here: isLess(other, bound, 1, mv) ) ==> all previous primes unlucky
868    q = p;
[6bbe94]869    D = mapinto(Dp); // shortcut CRA // shortcut CRA
[ad8e1b]870    for(int i=1; i<=mv; i++) // tighten bound
871      bound[i] = other[i];
872  }
873  // hopefully, we never reach this point
874  setReduce(a,true);
875  Off( SW_USE_QGCD );
[2156ec]876  D = gcdcfcg*gcd( f, g );
[ad8e1b]877  On( SW_USE_QGCD );
[713bdb]878  if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
[ad8e1b]879  return D;
880}
881
882
883int * leadDeg(const CanonicalForm & f, int *degs)
884{ // leading degree vector w.r.t. lex. monomial order x(i+1) > x(i)
885  // if f is in a coeff domain, the zero pointer is returned
886  // 'a' should point to an array of sufficient size level(f)+1
887  if(f.inCoeffDomain())
888    return 0;
889  CanonicalForm tmp = f;
890  do
891  {
892    degs[tmp.level()] = tmp.degree();
893    tmp = LC(tmp);
894  }
895  while(!tmp.inCoeffDomain());
896  return degs;
897}
898
899
900bool isLess(int *a, int *b, int lower, int upper)
901{ // compares the degree vectors a,b on the specified part. Note: x(i+1) > x(i)
902  for(int i=upper; i>=lower; i--)
903    if(a[i] == b[i])
904      continue;
905    else
906      return a[i] < b[i];
907  return true;
908}
909
910
911bool isEqual(int *a, int *b, int lower, int upper)
912{ // compares the degree vectors a,b on the specified part. Note: x(i+1) > x(i)
913  for(int i=lower; i<=upper; i++)
914    if(a[i] != b[i])
915      return false;
916  return true;
917}
918
919
920CanonicalForm firstLC(const CanonicalForm & f)
921{ // returns the leading coefficient (LC) of level <= 1
922  CanonicalForm ret = f;
923  while(ret.level() > 1)
924    ret = LC(ret);
925  return ret;
926}
927
928void tryExtgcd( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & M, CanonicalForm & result, CanonicalForm & s, CanonicalForm & t, bool & fail )
929{ // F, G are univariate polynomials (i.e. they have exactly one polynomial variable)
930  // F and G must have the same level AND level > 0
931  // we try to calculate gcd(F,G) = s*F + t*G
932  // if a zero divisor is encontered, 'fail' is set to one
933  // M is assumed to be monic
934  CanonicalForm P;
935  if(F.inCoeffDomain())
936  {
937    tryInvert( F, M, P, fail );
938    if(fail)
939      return;
940    result = 1;
941    s = P; t = 0;
942    return;
943  }
944  if(G.inCoeffDomain())
945  {
946    tryInvert( G, M, P, fail );
947    if(fail)
948      return;
949    result = 1;
950    s = 0; t = P;
951    return;
952  }
953  // here: both not inCoeffDomain
954  CanonicalForm inv, rem, tmp, u, v, q, sum=0;
955  if( F.degree() > G.degree() )
956  {
957    P = F; result = G;  s=v=0; t=u=1;
958  }
959  else
960  {
961    P = G; result = F; s=v=1; t=u=0;
962  }
963  Variable x = P.mvar();
964  // here: degree(P) >= degree(result)
965  while(true)
966  {
[fe2d4c]967    tryDivrem (P, result, q, rem, inv, M, fail);
[ad8e1b]968    if(fail)
969      return;
970    if( rem.isZero() )
971    {
972      s*=inv;
[4a05ed]973      s= reduce (s, M);
[ad8e1b]974      t*=inv;
[4a05ed]975      t= reduce (t, M);
[ad8e1b]976      result *= inv; // monify result
[4a05ed]977      result= reduce (result, M);
[ad8e1b]978      return;
979    }
980    sum += q;
981    if(result.degree(x) >= rem.degree(x))
982    {
983      P=result;
984      result=rem;
985      tmp=u-sum*s;
986      u=s;
987      s=tmp;
988      tmp=v-sum*t;
989      v=t;
990      t=tmp;
991      sum = 0; // reset
992    }
993    else
994      P = rem;
995  }
996}
997
998
999static CanonicalForm trycontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail )
1000{ // as 'content', but takes care of zero divisors
1001  ASSERT( x.level() > 0, "cannot calculate content with respect to algebraic variable" );
1002  Variable y = f.mvar();
1003  if ( y == x )
1004    return trycf_content( f, 0, M, fail );
1005  if ( y < x )
1006     return f;
1007  return swapvar( trycontent( swapvar( f, y, x ), y, M, fail ), y, x );
1008}
1009
1010
1011static CanonicalForm tryvcontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail )
1012{ // as vcontent, but takes care of zero divisors
1013  ASSERT( x.level() > 0, "cannot calculate vcontent with respect to algebraic variable" );
1014  if ( f.mvar() <= x )
1015    return trycontent( f, x, M, fail );
1016  CFIterator i;
1017  CanonicalForm d = 0, e, ret;
1018  for ( i = f; i.hasTerms() && ! d.isOne() && ! fail; i++ )
1019  {
1020    e = tryvcontent( i.coeff(), x, M, fail );
1021    if(fail)
1022      break;
1023    tryBrownGCD( d, e, M, ret, fail );
1024    d = ret;
1025  }
1026  return d;
1027}
1028
1029
1030static CanonicalForm trycf_content ( const CanonicalForm & f, const CanonicalForm & g, const CanonicalForm & M, bool & fail )
1031{ // as cf_content, but takes care of zero divisors
1032  if ( f.inPolyDomain() || ( f.inExtension() && ! getReduce( f.mvar() ) ) )
1033  {
1034    CFIterator i = f;
1035    CanonicalForm tmp = g, result;
1036    while ( i.hasTerms() && ! tmp.isOne() && ! fail )
1037    {
1038      tryBrownGCD( i.coeff(), tmp, M, result, fail );
1039      tmp = result;
1040      i++;
1041    }
1042    return result;
1043  }
1044  return abs( f );
1045}
1046
[4a05ed]1047void tryExtgcd( const CanonicalForm & F, const CanonicalForm & G, CanonicalForm & result, CanonicalForm & s, CanonicalForm & t, bool & fail )
1048{
1049  // F, G are univariate polynomials (i.e. they have exactly one polynomial variable)
1050  // F and G must have the same level AND level > 0
1051  // we try to calculate gcd(f,g) = s*F + t*G
1052  // if a zero divisor is encontered, 'fail' is set to one
1053  Variable a, b;
1054  if( !hasFirstAlgVar(F,a) && !hasFirstAlgVar(G,b) ) // note lazy evaluation
1055  {
1056    result = extgcd( F, G, s, t ); // no zero divisors possible
1057    return;
1058  }
1059  if( b.level() > a.level() )
1060    a = b;
1061  // here: a is the biggest alg. var in F and G
1062  CanonicalForm M = getMipo(a);
1063  CanonicalForm P;
1064  if( degree(F) > degree(G) )
1065  {
1066    P=F; result=G; s=0; t=1;
1067  }
1068  else
1069  {
1070    P=G; result=F; s=1; t=0;
1071  }
1072  CanonicalForm inv, rem, q, u, v;
1073  // here: degree(P) >= degree(result)
1074  while(true)
1075  {
1076    tryInvert( Lc(result), M, inv, fail );
1077    if(fail)
1078      return;
1079    // here: Lc(result) is invertible modulo M
1080    q = Lc(P)*inv * power( P.mvar(), degree(P)-degree(result) );
1081    rem = P - q*result;
1082    // here: s*F + t*G = result
1083    if( rem.isZero() )
1084    {
1085      s*=inv;
1086      t*=inv;
1087      result *= inv; // monify result
1088      return;
1089    }
1090    P=result;
1091    result=rem;
1092    rem=u-q*s;
1093    u=s;
1094    s=rem;
1095    rem=v-q*t;
1096    v=t;
1097    t=rem;
1098  }
1099}
1100
[359d742]1101void tryCRA( const CanonicalForm & x1, const CanonicalForm & q1, const CanonicalForm & x2, const CanonicalForm & q2, CanonicalForm & xnew, CanonicalForm & qnew, bool & fail )
1102{ // polys of level <= 1 are considered coefficients. q1,q2 are assumed to be coprime
1103  // xnew = x1 mod q1 (coefficientwise in the above sense)
1104  // xnew = x2 mod q2
1105  // qnew = q1*q2
1106  CanonicalForm tmp;
1107  if(x1.level() <= 1 && x2.level() <= 1) // base case
1108  {
1109    tryExtgcd(q1,q2,tmp,xnew,qnew,fail);
1110    if(fail)
1111      return;
1112    xnew = x1 + (x2-x1) * xnew * q1;
1113    qnew = q1*q2;
1114    xnew = mod(xnew,qnew);
1115    return;
1116  }
1117  CanonicalForm tmp2;
1118  xnew = 0;
1119  qnew = q1 * q2;
1120  // here: x1.level() > 1 || x2.level() > 1
1121  if(x1.level() > x2.level())
1122  {
1123    for(CFIterator i=x1; i.hasTerms(); i++)
1124    {
1125      if(i.exp() == 0) // const. term
1126      {
1127        tryCRA(i.coeff(),q1,x2,q2,tmp,tmp2,fail);
1128        if(fail)
1129          return;
1130        xnew += tmp;
1131      }
1132      else
1133      {
1134        tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
1135        if(fail)
1136          return;
1137        xnew += tmp * power(x1.mvar(),i.exp());
1138      }
1139    }
1140    return;
1141  }
1142  // here: x1.level() <= x2.level() && ( x1.level() > 1 || x2.level() > 1 )
1143  if(x2.level() > x1.level())
1144  {
1145    for(CFIterator j=x2; j.hasTerms(); j++)
1146    {
1147      if(j.exp() == 0) // const. term
1148      {
1149        tryCRA(x1,q1,j.coeff(),q2,tmp,tmp2,fail);
1150        if(fail)
1151          return;
1152        xnew += tmp;
1153      }
1154      else
1155      {
1156        tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
1157        if(fail)
1158          return;
1159        xnew += tmp * power(x2.mvar(),j.exp());
1160      }
1161    }
1162    return;
1163  }
1164  // here: x1.level() == x2.level() && x1.level() > 1 && x2.level() > 1
1165  CFIterator i = x1;
1166  CFIterator j = x2;
1167  while(i.hasTerms() || j.hasTerms())
1168  {
1169    if(i.hasTerms())
1170    {
1171      if(j.hasTerms())
1172      {
1173        if(i.exp() == j.exp())
1174        {
1175          tryCRA(i.coeff(),q1,j.coeff(),q2,tmp,tmp2,fail);
1176          if(fail)
1177            return;
1178          xnew += tmp * power(x1.mvar(),i.exp());
1179          i++; j++;
1180        }
1181        else
1182        {
1183          if(i.exp() < j.exp())
1184          {
1185            tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
1186            if(fail)
1187              return;
1188            xnew += tmp * power(x1.mvar(),i.exp());
1189            i++;
1190          }
1191          else // i.exp() > j.exp()
1192          {
1193            tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
1194            if(fail)
1195              return;
1196            xnew += tmp * power(x1.mvar(),j.exp());
1197            j++;
1198          }
1199        }
1200      }
1201      else // j is out of terms
1202      {
1203        tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
1204        if(fail)
1205          return;
1206        xnew += tmp * power(x1.mvar(),i.exp());
1207        i++;
1208      }
1209    }
1210    else // i is out of terms
1211    {
1212      tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
1213      if(fail)
1214        return;
1215      xnew += tmp * power(x1.mvar(),j.exp());
1216      j++;
1217    }
1218  }
1219}
1220
Note: See TracBrowser for help on using the repository browser.