source: git/factory/algext.cc @ 7d1c995

spielwiese
Last change on this file since 7d1c995 was 7d1c995, checked in by Martin Lee <martinlee84@…>, 12 years ago
added test to prevent multiple inclusion of headers moved function declarations from fieldGCD.h to algext.h deleted broken routine univarQGCD git-svn-id: file:///usr/local/Singular/svn/trunk@14253 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 26.5 KB
Line 
1#include "factoryconf.h"
2
3#ifdef HAVE_CSTDIO
4#include <cstdio>
5#else
6#include <stdio.h>
7#endif
8#ifndef NOSTREAMIO
9#ifdef HAVE_IOSTREAM_H
10#include <iostream.h>
11#elif defined(HAVE_IOSTREAM)
12#include <iostream>
13#endif
14#endif
15
16#include "cf_defs.h"
17#include "canonicalform.h"
18#include "cf_iter.h"
19#include "cf_primes.h"
20#include "cf_algorithm.h"
21#include "algext.h"
22#include "fieldGCD.h"
23#include "cf_map.h"
24#include "cf_generator.h"
25
26CanonicalForm reduce(const CanonicalForm & f, const CanonicalForm & M)
27{ // polynomials in M.mvar() are considered coefficients
28  // M univariate monic polynomial
29  // the coefficients of f are reduced modulo M
30  if(f.inBaseDomain() || f.level() < M.level())
31    return f;
32  if(f.level() == M.level())
33  {
34    if(f.degree() < M.degree())
35      return f;
36    CanonicalForm tmp = f;
37    do
38      tmp -= lc(tmp)*M*power(M.mvar(),tmp.degree()-M.degree());
39    while(tmp.degree() >= M.degree());
40    return tmp;
41  }
42  // here: f.level() > M.level()
43  CanonicalForm result = 0;
44  for(CFIterator i=f; i.hasTerms(); i++)
45    result += reduce(i.coeff(),M) * power(f.mvar(),i.exp());
46  return result;
47}
48
49void tryInvert( const CanonicalForm & F, const CanonicalForm & M, CanonicalForm & inv, bool & fail )
50{ // F, M are required to be "univariate" polynomials in an algebraic variable
51  // we try to invert F modulo M
52  if(F.inBaseDomain())
53  {
54    if(F.isZero())
55    {
56      fail = true;
57      return;
58    }
59    inv = 1/F;
60    return;
61  }
62  CanonicalForm b;
63  Variable a = M.mvar();
64  Variable x = Variable(1);
65  if(!extgcd( replacevar( F, a, x ), replacevar( M, a, x ), inv, b ).isOne())
66    fail = true;
67  else
68    inv = replacevar( inv, x, a ); // change back to alg var
69}
70
71void tryEuclid( const CanonicalForm & A, const CanonicalForm & B, const CanonicalForm & M, CanonicalForm & result, bool & fail )
72{
73  CanonicalForm P;
74  if(A.inCoeffDomain())
75  {
76    tryInvert( A, M, P, fail );
77    if(fail)
78      return;
79    result = 1;
80    return;
81  }
82  if(B.inCoeffDomain())
83  {
84    tryInvert( B, M, P, fail );
85    if(fail)
86      return;
87    result = 1;
88    return;
89  }
90  // here: both not inCoeffDomain
91  if( A.degree() > B.degree() )
92  {
93    P = A; result = B;
94  }
95  else
96  {
97    P = B; result = A;
98  }
99  CanonicalForm inv;
100  if( result.isZero() )
101  {
102    tryInvert( Lc(P), M, inv, fail );
103    if(fail)
104      return;
105    result = inv*P; // monify result (not reduced, yet)
106    return;
107  }
108  Variable x = P.mvar();
109  CanonicalForm rem;
110  // here: degree(P) >= degree(result)
111  while(true)
112  {
113    tryInvert( Lc(result), M, inv, fail );
114    if(fail)
115      return;
116    // here: Lc(result) is invertible modulo M
117    rem = reduce( P - Lc(P)*inv*result*power( x, P.degree(x)-result.degree(x) ), M );
118    if( rem.isZero() )
119    {
120      result *= inv;
121      return;
122    }
123    if(result.degree(x) >= rem.degree(x))
124    {
125      P = result;
126      result = rem;
127    }
128    else
129      P = rem;
130  }
131}
132
133bool hasFirstAlgVar( const CanonicalForm & f, Variable & a )
134{
135  if( f.inBaseDomain() ) // f has NO alg. variable
136    return false;
137  if( f.level()<0 ) // f has only alg. vars, so take the first one
138  {
139    a = f.mvar();
140    return true;
141  }
142  for(CFIterator i=f; i.hasTerms(); i++)
143    if( hasFirstAlgVar( i.coeff(), a ))
144      return true; // 'a' is already set
145  return false;
146}
147
148CanonicalForm QGCD( const CanonicalForm & F, const CanonicalForm & G );
149int * leadDeg(const CanonicalForm & f, int *degs);
150bool isLess(int *a, int *b, int lower, int upper);
151bool isEqual(int *a, int *b, int lower, int upper);
152CanonicalForm firstLC(const CanonicalForm & f);
153void tryCRA( const CanonicalForm & x1, const CanonicalForm & q1, const CanonicalForm & x2, const CanonicalForm & q2, const CanonicalForm & M, CanonicalForm & xnew, CanonicalForm & qnew, bool & fail );
154void tryExtgcd( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & M, CanonicalForm & result, CanonicalForm & s, CanonicalForm & t, bool & fail );
155static CanonicalForm trycontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail );
156static CanonicalForm tryvcontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail );
157static CanonicalForm trycf_content ( const CanonicalForm & f, const CanonicalForm & g, const CanonicalForm & M, bool & fail );
158static void tryDivide( const CanonicalForm & f, const CanonicalForm & g, const CanonicalForm & M, CanonicalForm & result, bool & divides, bool & fail );
159
160
161void tryBrownGCD( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & M, CanonicalForm & result, bool & fail )
162{ // assume F,G are multivariate polys over Z/p(a) for big prime p, M "univariate" polynomial in an algebraic variable
163  // M is assumed to be monic
164  if(F.isZero())
165  {
166    if(G.isZero())
167    {
168      result = G; // G is zero
169      return;
170    }
171    if(G.inCoeffDomain())
172    {
173      tryInvert(G,M,result,fail);
174      if(fail)
175        return;
176      result = 1;
177      return;
178    }
179    // try to make G monic modulo M
180    CanonicalForm inv;
181    tryInvert(Lc(G),M,inv,fail);
182    if(fail)
183      return;
184    result = inv*G;
185    return;
186  }
187  if(G.isZero()) // F is non-zero
188  {
189    if(F.inCoeffDomain())
190    {
191      tryInvert(F,M,result,fail);
192      if(fail)
193        return;
194      result = 1;
195      return;
196    }
197    // try to make F monic modulo M
198    CanonicalForm inv;
199    tryInvert(Lc(F),M,inv,fail);
200    if(fail)
201      return;
202    result = inv*F;
203    return;
204  }
205  // here: F,G both nonzero
206  if(F.inCoeffDomain())
207  {
208    tryInvert(F,M,result,fail);
209    if(fail)
210      return;
211    result = 1;
212    return;
213  }
214  if(G.inCoeffDomain())
215  {
216    tryInvert(G,M,result,fail);
217    if(fail)
218      return;
219    result = 1;
220    return;
221  }
222  CFMap MM,NN;
223  CFArray ps(1,2);
224  ps[1] = F;
225  ps[2] = G;
226  compress(ps,MM,NN); // maps MM, NN are created
227  CanonicalForm f=MM(F);
228  CanonicalForm g=MM(G);
229  // here: f,g are compressed
230  // compute largest variable in f or g (least one is Variable(1))
231  int mv = f.level();
232  if(g.level() > mv)
233    mv = g.level();
234  // here: mv is level of the largest variable in f, g
235  if(mv == 1) // f,g univariate
236  {
237    tryEuclid(f,g,M,result,fail);
238    if(fail)
239      return;
240    result = NN(result); // do not forget to map back
241    return;
242  }
243  // here: mv > 1
244  CanonicalForm cf = tryvcontent(f, Variable(2), M, fail); // cf is univariate poly in var(1)
245  if(fail)
246    return;
247  CanonicalForm cg = tryvcontent(g, Variable(2), M, fail);
248  if(fail)
249    return;
250  CanonicalForm c;
251  tryEuclid(cf,cg,M,c,fail);
252  if(fail)
253    return;
254  bool divides = true;
255  CanonicalForm tmp;
256  // f /= cf
257  tryDivide(f,cf,M,tmp,divides,fail); // 'divides' is not checked
258  if(fail)
259    return;
260  f = tmp;
261  // g /= cg
262  tryDivide(g,cg,M,tmp,divides,fail); // 'divides' is not checked
263  if(fail)
264    return;
265  g = tmp;
266  if(f.inCoeffDomain())
267  {
268    tryInvert(f,M,result,fail);
269    if(fail)
270      return;
271    result = NN(c);
272    return;
273  }
274  if(g.inCoeffDomain())
275  {
276    tryInvert(g,M,result,fail);
277    if(fail)
278      return;
279    result = NN(c);
280    return;
281  }
282  int *L = new int[mv+1]; // L is addressed by i from 2 to mv
283  int *N = new int[mv+1];
284  for(int i=2; i<=mv; i++)
285    L[i] = N[i] = 0;
286  L = leadDeg(f, L);
287  N = leadDeg(g, N);
288  CanonicalForm gamma;
289  tryEuclid( firstLC(f), firstLC(g), M, gamma, fail );
290  if(fail)
291    return;
292  for(int i=2; i<=mv; i++) // entries at i=0,1 not visited
293    if(N[i] < L[i])
294      L[i] = N[i];
295  // L is now upper bound for degrees of gcd
296  int *dg_im = new int[mv+1]; // for the degree vector of the image we don't need any entry at i=1
297  for(int i=2; i<=mv; i++)
298    dg_im[i] = 0; // initialize
299  CanonicalForm gamma_image, m=1;
300  CanonicalForm gm=0;
301  CanonicalForm g_image, alpha, gnew, mnew;
302  FFGenerator gen = FFGenerator();
303  for(FFGenerator gen = FFGenerator(); gen.hasItems(); gen.next())
304  {
305    alpha = gen.item();
306    gamma_image = reduce(gamma(alpha, Variable(1)),M); // plug in alpha for var(1)
307    if(gamma_image.isZero()) // skip lc-bad points var(1)-alpha
308      continue;
309    tryBrownGCD( f(alpha, Variable(1)), g(alpha, Variable(1)), M, g_image, fail ); // recursive call with one var less
310    if(fail)
311      return;
312    g_image = reduce(g_image, M);
313    if(g_image.inCoeffDomain()) // early termination
314    {
315      tryInvert(g_image,M,result,fail);
316      if(fail)
317        return;
318      result = NN(c);
319      return;
320    }
321    for(int i=2; i<=mv; i++)
322      dg_im[i] = 0; // reset (this is necessary, because some entries may not be updated by call to leadDeg)
323    dg_im = leadDeg(g_image, dg_im); // dg_im cannot be NIL-pointer
324    if(isEqual(dg_im, L, 2, mv))
325    {
326      g_image /= lc(g_image); // make g_image monic over Z/p
327      g_image *= gamma_image; // multiply by multiple of image lc(gcd)
328      tryCRA( g_image, Variable(1)-alpha, gm, m, M, gnew, mnew, fail );
329      // gnew = gm mod m
330      // gnew = g_image mod var(1)-alpha
331      // mnew = m * (var(1)-alpha)
332      if(fail)
333        return;
334      m = mnew;
335      if(gnew == gm) // gnew did not change
336      {
337        cf = tryvcontent(gm, Variable(2), M, fail);
338        if(fail)
339          return;
340        divides = true;
341        tryDivide(gm,cf,M,g_image,divides,fail); // 'divides' is ignored
342        if(fail)
343          return;
344        tryDivide(f,g_image,M,tmp,divides,fail); // trial division (f)
345        if(fail)
346          return;
347        if(divides)
348        {
349          tryDivide(g,g_image,M,tmp,divides,fail); // trial division (g)
350          if(fail)
351            return;
352          if(divides)
353          {
354            result = NN(c*g_image);
355            return;
356          }
357        }
358      }
359      gm = gnew;
360      continue;
361    }
362
363    if(isLess(L, dg_im, 2, mv)) // dg_im > L --> current point unlucky
364      continue;
365
366    // here: isLess(dg_im, L, 2, mv) --> all previous points were unlucky
367    m = CanonicalForm(1); // reset
368    gm = 0; // reset
369    for(int i=2; i<=mv; i++) // tighten bound
370      L[i] = dg_im[i];
371  }
372  // we are out of evaluation points
373  fail = true;
374}
375
376CanonicalForm QGCD( const CanonicalForm & F, const CanonicalForm & G )
377{ // f,g in Q(a)[x1,...,xn]
378  if(F.isZero())
379  {
380    if(G.isZero())
381      return G; // G is zero
382    if(G.inCoeffDomain())
383      return CanonicalForm(1);
384    return G/Lc(G); // return monic G
385  }
386  if(G.isZero()) // F is non-zero
387  {
388    if(F.inCoeffDomain())
389      return CanonicalForm(1);
390    return F/Lc(F); // return monic F
391  }
392  if(F.inCoeffDomain() || G.inCoeffDomain())
393    return CanonicalForm(1);
394  // here: both NOT inCoeffDomain
395  CanonicalForm f, g, tmp, M, q, D, Dp, cl, newq, mipo;
396  int p, i;
397  int *bound, *other; // degree vectors
398  bool fail;
399  bool off_rational=!isOn(SW_RATIONAL);
400  On( SW_RATIONAL ); // needed by bCommonDen
401  f = F * bCommonDen(F);
402  g = G * bCommonDen(G);
403  Variable a, b;
404  if(hasFirstAlgVar(f,a))
405  {
406    if(hasFirstAlgVar(g,b))
407    {
408      if(b.level() > a.level())
409        a = b;
410    }
411  }
412  else
413  {
414    if(!hasFirstAlgVar(g,a))// both not in extension
415    {
416      Off( SW_RATIONAL );
417      Off( SW_USE_QGCD );
418      tmp = gcd( F, G );
419      On( SW_USE_QGCD );
420      if (off_rational) Off(SW_RATIONAL);
421      return tmp;
422    }
423  }
424  // here: a is the biggest alg. var in f and g AND some of f,g is in extension
425  // (in the sequel b is used to swap alg/poly vars)
426  setReduce(a,false); // do not reduce expressions modulo mipo
427  tmp = getMipo(a);
428  M = tmp * bCommonDen(tmp);
429  // here: f, g in Z[a][x1,...,xn], M in Z[a] not necessarily monic
430  Off( SW_RATIONAL ); // needed by mod
431  // calculate upper bound for degree vector of gcd
432  int mv = f.level(); i = g.level();
433  if(i > mv)
434    mv = i;
435  // here: mv is level of the largest variable in f, g
436  b = Variable(mv+1);
437  bound = new int[mv+1]; // 'bound' could be indexed from 0 to mv, but we will only use from 1 to mv
438  other = new int[mv+1];
439  for(int i=1; i<=mv; i++) // initialize 'bound', 'other' with zeros
440    bound[i] = other[i] = 0;
441  bound = leadDeg(f,bound); // 'bound' is set the leading degree vector of f
442  other = leadDeg(g,other);
443  for(int i=1; i<=mv; i++) // entry at i=0 not visited
444    if(other[i] < bound[i])
445      bound[i] = other[i];
446  // now 'bound' is the smaller vector
447  cl = lc(M) * lc(f) * lc(g);
448  q = 1;
449  D = 0;
450  for( i=cf_getNumBigPrimes()-1; i>-1; i-- )
451  {
452    p = cf_getBigPrime(i);
453    if( mod( cl, p ).isZero() ) // skip lc-bad primes
454      continue;
455    fail = false;
456    setCharacteristic(p);
457    mipo = mapinto(M);
458    mipo /= mipo.lc();
459    // here: mipo is monic
460    tryBrownGCD( mapinto(f), mapinto(g), mipo, Dp, fail );
461    Dp = reduce( Dp, mipo );
462    setCharacteristic(0);
463    if( fail ) // mipo splits in char p
464      continue;
465    if( Dp.inCoeffDomain() ) // early termination
466    {
467      tryInvert(Dp,mipo,tmp,fail); // check if zero divisor
468      if(fail)
469        continue;
470      setReduce(a,true);
471      if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
472      return CanonicalForm(1);
473    }
474    // here: Dp NOT inCoeffDomain
475    for(int i=1; i<=mv; i++)
476      other[i] = 0; // reset (this is necessary, because some entries may not be updated by call to leadDeg)
477    other = leadDeg(Dp,other);
478
479    if(isEqual(bound, other, 1, mv)) // equal
480    {
481      chineseRemainder( D, q, replacevar( mapinto(Dp), a, b ), p, tmp, newq );
482      // tmp = Dp mod p
483      // tmp = D mod q
484      // newq = p*q
485      q = newq;
486      if( D != tmp )
487        D = tmp;
488      On( SW_RATIONAL );
489      tmp = replacevar( Farey( D, q ), b, a ); // Farey and switch back to alg var
490      setReduce(a,true); // reduce expressions modulo mipo
491      On( SW_RATIONAL ); // needed by fdivides
492      if( fdivides( tmp, f ) && fdivides( tmp, g )) // trial division
493      {
494        Off( SW_RATIONAL );
495        setReduce(a,true);
496        if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
497        return tmp;
498      }
499      Off( SW_RATIONAL );
500      setReduce(a,false); // do not reduce expressions modulo mipo
501      continue;
502    }
503    if( isLess(bound, other, 1, mv) ) // current prime unlucky
504      continue;
505    // here: isLess(other, bound, 1, mv) ) ==> all previous primes unlucky
506    q = p;
507    D = replacevar( mapinto(Dp), a, b ); // shortcut CRA // shortcut CRA
508    for(int i=1; i<=mv; i++) // tighten bound
509      bound[i] = other[i];
510  }
511  // hopefully, we never reach this point
512  setReduce(a,true);
513  Off( SW_USE_QGCD );
514  D = gcd( f, g );
515  On( SW_USE_QGCD );
516  if (off_rational) Off(SW_RATIONAL); else On(SW_RATIONAL);
517  return D;
518}
519
520
521int * leadDeg(const CanonicalForm & f, int *degs)
522{ // leading degree vector w.r.t. lex. monomial order x(i+1) > x(i)
523  // if f is in a coeff domain, the zero pointer is returned
524  // 'a' should point to an array of sufficient size level(f)+1
525  if(f.inCoeffDomain())
526    return 0;
527  CanonicalForm tmp = f;
528  do
529  {
530    degs[tmp.level()] = tmp.degree();
531    tmp = LC(tmp);
532  }
533  while(!tmp.inCoeffDomain());
534  return degs;
535}
536
537
538bool isLess(int *a, int *b, int lower, int upper)
539{ // compares the degree vectors a,b on the specified part. Note: x(i+1) > x(i)
540  for(int i=upper; i>=lower; i--)
541    if(a[i] == b[i])
542      continue;
543    else
544      return a[i] < b[i];
545  return true;
546}
547
548
549bool isEqual(int *a, int *b, int lower, int upper)
550{ // compares the degree vectors a,b on the specified part. Note: x(i+1) > x(i)
551  for(int i=lower; i<=upper; i++)
552    if(a[i] != b[i])
553      return false;
554  return true;
555}
556
557
558CanonicalForm firstLC(const CanonicalForm & f)
559{ // returns the leading coefficient (LC) of level <= 1
560  CanonicalForm ret = f;
561  while(ret.level() > 1)
562    ret = LC(ret);
563  return ret;
564}
565
566
567void tryCRA( const CanonicalForm & x1, const CanonicalForm & q1, const CanonicalForm & x2, const CanonicalForm & q2, const CanonicalForm & M, CanonicalForm & xnew, CanonicalForm & qnew, bool & fail )
568{ // as CRA, but takes care of zero divisors
569  CanonicalForm tmp;
570  if(x1.level() <= 1 && x2.level() <= 1) // base case
571  {
572    tryExtgcd(q1,q2,M,tmp,xnew,qnew,fail);
573    if(fail)
574      return;
575    xnew = x1 + (x2-x1) * xnew * q1;
576    qnew = q1*q2;
577    xnew = mod(xnew,qnew);
578    return;
579  }
580  CanonicalForm tmp2;
581  xnew = 0;
582  qnew = q1 * q2;
583  // here: x1.level() > 1 || x2.level() > 1
584  if(x1.level() > x2.level())
585  {
586    for(CFIterator i=x1; i.hasTerms(); i++)
587    {
588      if(i.exp() == 0) // const. term
589      {
590        tryCRA(i.coeff(),q1,x2,q2,M,tmp,tmp2,fail);
591        if(fail)
592          return;
593        xnew += tmp;
594      }
595      else
596      {
597        tryCRA(i.coeff(),q1,0,q2,M,tmp,tmp2,fail);
598        if(fail)
599          return;
600        xnew += tmp * power(x1.mvar(),i.exp());
601      }
602    }
603    return;
604  }
605  // here: x1.level() <= x2.level() && ( x1.level() > 1 || x2.level() > 1 )
606  if(x2.level() > x1.level())
607  {
608    for(CFIterator j=x2; j.hasTerms(); j++)
609    {
610      if(j.exp() == 0) // const. term
611      {
612        tryCRA(x1,q1,j.coeff(),q2,M,tmp,tmp2,fail);
613        if(fail)
614          return;
615        xnew += tmp;
616      }
617      else
618      {
619        tryCRA(0,q1,j.coeff(),q2,M,tmp,tmp2,fail);
620        if(fail)
621          return;
622        xnew += tmp * power(x2.mvar(),j.exp());
623      }
624    }
625    return;
626  }
627  // here: x1.level() == x2.level() && x1.level() > 1 && x2.level() > 1
628  CFIterator i = x1;
629  CFIterator j = x2;
630  while(i.hasTerms() || j.hasTerms())
631  {
632    if(i.hasTerms())
633    {
634      if(j.hasTerms())
635      {
636        if(i.exp() == j.exp())
637        {
638          tryCRA(i.coeff(),q1,j.coeff(),q2,M,tmp,tmp2,fail);
639          if(fail)
640            return;
641          xnew += tmp * power(x1.mvar(),i.exp());
642          i++; j++;
643        }
644        else
645        {
646          if(i.exp() < j.exp())
647          {
648            tryCRA(i.coeff(),q1,0,q2,M,tmp,tmp2,fail);
649            if(fail)
650              return;
651            xnew += tmp * power(x1.mvar(),i.exp());
652            i++;
653          }
654          else // i.exp() > j.exp()
655          {
656            tryCRA(0,q1,j.coeff(),q2,M,tmp,tmp2,fail);
657            if(fail)
658              return;
659            xnew += tmp * power(x1.mvar(),j.exp());
660            j++;
661          }
662        }
663      }
664      else // j is out of terms
665      {
666        tryCRA(i.coeff(),q1,0,q2,M,tmp,tmp2,fail);
667        if(fail)
668          return;
669        xnew += tmp * power(x1.mvar(),i.exp());
670        i++;
671      }
672    }
673    else // i is out of terms
674    {
675      tryCRA(0,q1,j.coeff(),q2,M,tmp,tmp2,fail);
676      if(fail)
677        return;
678      xnew += tmp * power(x1.mvar(),j.exp());
679      j++;
680    }
681  }
682}
683
684
685void tryExtgcd( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & M, CanonicalForm & result, CanonicalForm & s, CanonicalForm & t, bool & fail )
686{ // F, G are univariate polynomials (i.e. they have exactly one polynomial variable)
687  // F and G must have the same level AND level > 0
688  // we try to calculate gcd(F,G) = s*F + t*G
689  // if a zero divisor is encontered, 'fail' is set to one
690  // M is assumed to be monic
691  CanonicalForm P;
692  if(F.inCoeffDomain())
693  {
694    tryInvert( F, M, P, fail );
695    if(fail)
696      return;
697    result = 1;
698    s = P; t = 0;
699    return;
700  }
701  if(G.inCoeffDomain())
702  {
703    tryInvert( G, M, P, fail );
704    if(fail)
705      return;
706    result = 1;
707    s = 0; t = P;
708    return;
709  }
710  // here: both not inCoeffDomain
711  CanonicalForm inv, rem, tmp, u, v, q, sum=0;
712  if( F.degree() > G.degree() )
713  {
714    P = F; result = G;  s=v=0; t=u=1;
715  }
716  else
717  {
718    P = G; result = F; s=v=1; t=u=0;
719  }
720  Variable x = P.mvar();
721  // here: degree(P) >= degree(result)
722  while(true)
723  {
724    tryInvert( Lc(result), M, inv, fail );
725    if(fail)
726      return;
727    // here: Lc(result) is invertible modulo M
728    q = Lc(P)*inv*power( x, P.degree(x)-result.degree(x) );
729    rem = reduce( P - q*result, M );
730    if( rem.isZero() )
731    {
732      s*=inv;
733      t*=inv;
734      result *= inv; // monify result
735      return;
736    }
737    sum += q;
738    if(result.degree(x) >= rem.degree(x))
739    {
740      P=result;
741      result=rem;
742      tmp=u-sum*s;
743      u=s;
744      s=tmp;
745      tmp=v-sum*t;
746      v=t;
747      t=tmp;
748      sum = 0; // reset
749    }
750    else
751      P = rem;
752  }
753}
754
755
756static CanonicalForm trycontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail )
757{ // as 'content', but takes care of zero divisors
758  ASSERT( x.level() > 0, "cannot calculate content with respect to algebraic variable" );
759  Variable y = f.mvar();
760  if ( y == x )
761    return trycf_content( f, 0, M, fail );
762  if ( y < x )
763     return f;
764  return swapvar( trycontent( swapvar( f, y, x ), y, M, fail ), y, x );
765}
766
767
768static CanonicalForm tryvcontent ( const CanonicalForm & f, const Variable & x, const CanonicalForm & M, bool & fail )
769{ // as vcontent, but takes care of zero divisors
770  ASSERT( x.level() > 0, "cannot calculate vcontent with respect to algebraic variable" );
771  if ( f.mvar() <= x )
772    return trycontent( f, x, M, fail );
773  CFIterator i;
774  CanonicalForm d = 0, e, ret;
775  for ( i = f; i.hasTerms() && ! d.isOne() && ! fail; i++ )
776  {
777    e = tryvcontent( i.coeff(), x, M, fail );
778    if(fail)
779      break;
780    tryBrownGCD( d, e, M, ret, fail );
781    d = ret;
782  }
783  return d;
784}
785
786
787static CanonicalForm trycf_content ( const CanonicalForm & f, const CanonicalForm & g, const CanonicalForm & M, bool & fail )
788{ // as cf_content, but takes care of zero divisors
789  if ( f.inPolyDomain() || ( f.inExtension() && ! getReduce( f.mvar() ) ) )
790  {
791    CFIterator i = f;
792    CanonicalForm tmp = g, result;
793    while ( i.hasTerms() && ! tmp.isOne() && ! fail )
794    {
795      tryBrownGCD( i.coeff(), tmp, M, result, fail );
796      tmp = result;
797      i++;
798    }
799    return result;
800  }
801  return abs( f );
802}
803
804
805static void tryDivide( const CanonicalForm & f, const CanonicalForm & g, const CanonicalForm & M, CanonicalForm & result, bool & divides, bool & fail )
806{ // M "univariate" monic polynomial
807  // f, g polynomials with coeffs modulo M.
808  // if f is divisible by g, 'divides' is set to 1 and 'result' == f/g mod M coefficientwise.
809  // 'fail' is set to 1, iff a zero divisor is encountered.
810  // divides==1 implies fail==0
811  // required: getReduce(M.mvar())==0
812  if(g.inBaseDomain())
813  {
814    result = f/g;
815    divides = true;
816    return;
817  }
818  if(g.inCoeffDomain())
819  {
820    tryInvert(g,M,result,fail);
821    if(fail)
822      return;
823    result = reduce(f*result, M);
824    divides = true;
825    return;
826  }
827  // here: g NOT inCoeffDomain
828  Variable x = g.mvar();
829  if(f.degree(x) < g.degree(x))
830  {
831    divides = false;
832    return;
833  }
834  // here: f.degree(x) > 0 and f.degree(x) >= g.degree(x)
835  CanonicalForm F = f;
836  CanonicalForm q, leadG = LC(g);
837  result = 0;
838  while(!F.isZero())
839  {
840    tryDivide(F.LC(x),leadG,M,q,divides,fail);
841    if(fail || !divides)
842      return;
843    if(F.degree(x)<g.degree(x))
844    {
845      divides = false;
846      return;
847    }
848    q *= power(x,F.degree(x)-g.degree(x));
849    result += q;
850    F = reduce(F-q*g, M);
851  }
852  result = reduce(result, M);
853  divides = true;
854}
855
856
857
858void tryCRA( const CanonicalForm & x1, const CanonicalForm & q1, const CanonicalForm & x2, const CanonicalForm & q2, CanonicalForm & xnew, CanonicalForm & qnew, bool & fail )
859{ // polys of level <= 1 are considered coefficients. q1,q2 are assumed to be coprime
860  // xnew = x1 mod q1 (coefficientwise in the above sense)
861  // xnew = x2 mod q2
862  // qnew = q1*q2
863  CanonicalForm tmp;
864  if(x1.level() <= 1 && x2.level() <= 1) // base case
865  {
866    tryExtgcd(q1,q2,tmp,xnew,qnew,fail);
867    if(fail)
868      return;
869    xnew = x1 + (x2-x1) * xnew * q1;
870    qnew = q1*q2;
871    xnew = mod(xnew,qnew);
872    return;
873  }
874  CanonicalForm tmp2;
875  xnew = 0;
876  qnew = q1 * q2;
877  // here: x1.level() > 1 || x2.level() > 1
878  if(x1.level() > x2.level())
879  {
880    for(CFIterator i=x1; i.hasTerms(); i++)
881    {
882      if(i.exp() == 0) // const. term
883      {
884        tryCRA(i.coeff(),q1,x2,q2,tmp,tmp2,fail);
885        if(fail)
886          return;
887        xnew += tmp;
888      }
889      else
890      {
891        tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
892        if(fail)
893          return;
894        xnew += tmp * power(x1.mvar(),i.exp());
895      }
896    }
897    return;
898  }
899  // here: x1.level() <= x2.level() && ( x1.level() > 1 || x2.level() > 1 )
900  if(x2.level() > x1.level())
901  {
902    for(CFIterator j=x2; j.hasTerms(); j++)
903    {
904      if(j.exp() == 0) // const. term
905      {
906        tryCRA(x1,q1,j.coeff(),q2,tmp,tmp2,fail);
907        if(fail)
908          return;
909        xnew += tmp;
910      }
911      else
912      {
913        tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
914        if(fail)
915          return;
916        xnew += tmp * power(x2.mvar(),j.exp());
917      }
918    }
919    return;
920  }
921  // here: x1.level() == x2.level() && x1.level() > 1 && x2.level() > 1
922  CFIterator i = x1;
923  CFIterator j = x2;
924  while(i.hasTerms() || j.hasTerms())
925  {
926    if(i.hasTerms())
927    {
928      if(j.hasTerms())
929      {
930        if(i.exp() == j.exp())
931        {
932          tryCRA(i.coeff(),q1,j.coeff(),q2,tmp,tmp2,fail);
933          if(fail)
934            return;
935          xnew += tmp * power(x1.mvar(),i.exp());
936          i++; j++;
937        }
938        else
939        {
940          if(i.exp() < j.exp())
941          {
942            tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
943            if(fail)
944              return;
945            xnew += tmp * power(x1.mvar(),i.exp());
946            i++;
947          }
948          else // i.exp() > j.exp()
949          {
950            tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
951            if(fail)
952              return;
953            xnew += tmp * power(x1.mvar(),j.exp());
954            j++;
955          }
956        }
957      }
958      else // j is out of terms
959      {
960        tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
961        if(fail)
962          return;
963        xnew += tmp * power(x1.mvar(),i.exp());
964        i++;
965      }
966    }
967    else // i is out of terms
968    {
969      tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
970      if(fail)
971        return;
972      xnew += tmp * power(x1.mvar(),j.exp());
973      j++;
974    }
975  }
976}
977
978
979void tryExtgcd( const CanonicalForm & F, const CanonicalForm & G, CanonicalForm & result, CanonicalForm & s, CanonicalForm & t, bool & fail )
980{
981  // F, G are univariate polynomials (i.e. they have exactly one polynomial variable)
982  // F and G must have the same level AND level > 0
983  // we try to calculate gcd(f,g) = s*F + t*G
984  // if a zero divisor is encontered, 'fail' is set to one
985  Variable a, b;
986  if( !hasFirstAlgVar(F,a) && !hasFirstAlgVar(G,b) ) // note lazy evaluation
987  {
988    result = extgcd( F, G, s, t ); // no zero divisors possible
989    return;
990  }
991  if( b.level() > a.level() )
992    a = b;
993  // here: a is the biggest alg. var in F and G
994  CanonicalForm M = getMipo(a);
995  CanonicalForm P;
996  if( degree(F) > degree(G) )
997  {
998    P=F; result=G; s=0; t=1;
999  }
1000  else
1001  {
1002    P=G; result=F; s=1; t=0;
1003  }
1004  CanonicalForm inv, rem, q, u, v;
1005  // here: degree(P) >= degree(result)
1006  while(true)
1007  {
1008    tryInvert( Lc(result), M, inv, fail );
1009    if(fail)
1010      return;
1011    // here: Lc(result) is invertible modulo M
1012    q = Lc(P)*inv * power( P.mvar(), degree(P)-degree(result) );
1013    rem = P - q*result;
1014    // here: s*F + t*G = result
1015    if( rem.isZero() )
1016    {
1017      s*=inv;
1018      t*=inv;
1019      result *= inv; // monify result
1020      return;
1021    }
1022    P=result;
1023    result=rem;
1024    rem=u-q*s;
1025    u=s;
1026    s=rem;
1027    rem=v-q*t;
1028    v=t;
1029    t=rem;
1030  }
1031}
Note: See TracBrowser for help on using the repository browser.