source: git/factory/algext.cc @ 4dd2c4

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