source: git/factory/algext.cc @ d56aae9

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