source: git/factory/algext.cc @ 6c44098

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