source: git/factory/algext.cc @ 276c3f

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