source: git/factory/algext.cc @ 806c18

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