source: git/factory/algext.cc @ 69b66ef

fieker-DuValspielwiese
Last change on this file since 69b66ef was 359d742, checked in by Hans Schönemann <hannes@…>, 16 years ago
*hannens: new versions:EZGCD_P,QGCD git-svn-id: file:///usr/local/Singular/svn/trunk@10782 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 16.1 KB
Line 
1#include <stdio.h>
2#include <iostream.h>
3#include <config.h>
4
5#include "cf_defs.h"
6#include "canonicalform.h"
7#include "cf_iter.h"
8#include "cf_primes.h"
9#include "cf_algorithm.h"
10#include "algext.h"
11#include "fieldGCD.h"
12#include "cf_map.h"
13#include "cf_generator.h"
14
15void tryEuclid( const CanonicalForm & A, const CanonicalForm & B, const CanonicalForm M, CanonicalForm & result, bool & fail )
16{
17  CanonicalForm P;
18  if( degree(A) > degree(B) )
19  {
20    P = A; result = B;
21  }
22  else
23  {
24    P = B; result = A;
25  }
26  if( P.isZero() ) // then result is zero, too
27    return;
28  CanonicalForm inv;
29  if( result.isZero() )
30  {
31    tryInvert( Lc(P), M, inv, fail );
32    if(fail)
33      return;
34    result = inv*P; // monify result
35    return;
36  }
37  CanonicalForm rem;
38  // here: degree(P) >= degree(result)
39  while(true)
40  {
41    tryInvert( Lc(result), M, inv, fail );
42    if(fail)
43      return;
44    // here: Lc(result) is invertible modulo M
45    rem = P - Lc(P)*inv*result * power( P.mvar(), degree(P)-degree(result) );
46    if( rem.isZero() )
47    {
48      result *= inv; // monify result
49      return;
50    }
51    P = result;
52    result = rem;
53  }
54}
55
56
57void tryInvert( const CanonicalForm & F, const CanonicalForm & M, CanonicalForm & inv, bool & fail )
58{
59  // F, M are required to be "univariate" polynomials in an algebraic variable
60  // we try to invert F modulo M
61  CanonicalForm b;
62  Variable a = M.mvar();
63  Variable x = Variable(1);
64  if(!extgcd( replacevar( F, a, x ), replacevar( M, a, x ), inv, b ).isOne())
65  {
66    printf("failed ");
67    fail = true;
68  }
69  else
70    inv = replacevar( inv, a, x); // change back to alg var
71}
72
73
74bool hasFirstAlgVar( const CanonicalForm & f, Variable & a )
75{
76  if( f.inBaseDomain() ) // f has NO alg. variable
77    return false;
78
79  if( f.level()<0 ) // f has only alg. vars, so take the first one
80  {
81    a = f.mvar();
82    return true;
83  }
84  for(CFIterator i=f; i.hasTerms(); i++)
85    if( hasFirstAlgVar( i.coeff(), a ))
86      return true; // 'a' is already set
87
88  return false;
89}
90
91CanonicalForm univarQGCD( const CanonicalForm & F, const CanonicalForm & G )
92{ // F,G in Q(a)[x]
93  CanonicalForm f, g, tmp, M, q, D, Dp, cl, newD, newq;
94  int p, dp_deg, bound, i;
95  bool fail;
96  On(SW_RATIONAL);
97  f = F * bCommonDen(F);
98  g = G * bCommonDen(G);
99  Variable a,b;
100  if( !hasFirstAlgVar( f, a ) && !hasFirstAlgVar( g, b ))
101  {
102    // F and G are in Q[x], call...
103#ifdef HAVE_NTL
104    if ( isOn( SW_USE_NTL_GCD_0 ))
105      return gcd_univar_ntl0( f, g );
106#endif
107    return gcd_poly_univar0( f, g, false );
108  }
109  if( b.level() > a.level() )
110    a = b;
111  // here: a is the biggest alg. var in f and g
112  tmp = getMipo(a);
113  M = tmp * bCommonDen(tmp);
114  Off(SW_RATIONAL);
115  // calculate upper bound for degree of gcd
116  bound = degree(f);
117  i = degree(g);
118  if( i < bound )
119    bound = i;
120
121  cl = lc(M) * lc(f) * lc(g);
122  q = 1;
123  D = 0;
124  for(i=cf_getNumBigPrimes()-1; i>-1; i--)
125  {
126    p = cf_getBigPrime(i);
127    if( mod( cl, p ).isZero() ) // skip lc-bad primes
128      continue;
129
130    fail = false;
131    setCharacteristic(p);
132    tryEuclid( mapinto(f), mapinto(g), mapinto(M), Dp, fail );
133    setCharacteristic(0);
134    if( fail ) // M splits in char p
135      continue;
136
137    dp_deg = degree(Dp);
138
139    if( dp_deg == 0 ) // early termination
140    {
141      CanonicalForm inv;
142      tryInvert(Dp, M, inv, fail);
143      if(fail)
144        continue;
145      return CanonicalForm(1);
146    }
147
148    if( dp_deg > bound ) // current prime unlucky
149      continue;
150
151    if( dp_deg < bound ) // all previous primes unlucky
152    {
153      q = p;
154      D = mapinto(Dp); // shortcut CRA
155      bound = dp_deg; // tighten bound
156      continue;
157    }
158    chineseRemainder( D, q, mapinto(Dp), p, newD, newq );
159    // newD = Dp mod p
160    // newD = D mod q
161    // newq = p*q
162    q = newq;
163    if( D != newD )
164    {
165      D = newD;
166      continue;
167    }
168    On( SW_RATIONAL );
169    tmp = Farey( D, q );
170    if( fdivides( tmp, f ) && fdivides( tmp, g )) // trial division
171    {
172      Off( SW_RATIONAL );
173      return tmp;
174    }
175    Off( SW_RATIONAL );
176  }
177  // hopefully, we never reach this point
178  Off( SW_USE_QGCD );
179  D = gcd( f, g );
180  On( SW_USE_QGCD );
181  return D;
182}
183
184
185CanonicalForm QGCD( const CanonicalForm & F, const CanonicalForm & G )
186{ // F,G in Q(a)[x1,...,xn]
187  if(F.isZero())
188  {
189    if(G.isZero())
190      return G; // G is zero
191    if(G.inCoeffDomain())
192      return CanonicalForm(1);
193    return G/Lc(G); // return monic G
194  }
195  if(G.isZero()) // F is non-zero
196  {
197    if(F.inCoeffDomain())
198      return CanonicalForm(1);
199    return F/Lc(F); // return monic F
200  }
201  if(F.inCoeffDomain() || G.inCoeffDomain())
202    return CanonicalForm(1);
203
204  CanonicalForm D;
205  if (getCharacteristic()==0)
206  {
207    CanonicalForm f,g,tmp, M, q, Dp, cl, newD, newq;
208    int p, i;
209    int *bound, *other; // degree vectors
210    bool fail;
211    On(SW_RATIONAL);
212    f = F * bCommonDen(F);
213    g = G * bCommonDen(G);
214    Variable a,b;
215    if( !hasFirstAlgVar( f, a ) && !hasFirstAlgVar( g, b ))
216    {
217      // F and G are in Q[x1,...,xn], call...
218      return gcd_poly_0( f, g );
219    }
220    if( b.level() > a.level() )
221      a = b;
222    // here: a is the biggest alg. var in f and g
223    tmp = getMipo(a);
224    M = tmp * bCommonDen(tmp);
225    Off( SW_RATIONAL );
226    // here: f, g in Z[y][x1,...,xn], M in Z[y] not necessarily monic
227    // calculate upper bound for degree of gcd
228    int mv = f.level();
229    if(g.level() > mv)
230      mv = g.level();
231    // here: mv is level of the largest variable in f, g
232    bound = new int[mv+1];
233    other = new int[mv+1];
234    for(int i=1; i<=mv; i++)
235      bound[i] = other[i] = 0;
236    bound = leadDeg(f,bound);
237    other = leadDeg(g,other);
238    for(int i=1; i<=mv; i++) // entry at i=0 is not visited
239      if(other[i] < bound[i])
240        bound[i] = other[i];
241    // now bound points on the smaller vector
242    cl = lc(M) * lc(f) * lc(g);
243    q = 1;
244    D = 0;
245    for(int i=cf_getNumBigPrimes()-1; i>-1; i--)
246    {
247      p = cf_getBigPrime(i);
248      if( mod( cl, p ).isZero() ) // skip lc-bad primes
249        continue;
250
251      fail = false;
252      setCharacteristic(p);
253      tryBrownGCD( mapinto(f), mapinto(g), mapinto(M), Dp, fail );
254      setCharacteristic(0);
255      if( fail ) // M splits in char p
256        continue;
257
258      for(int i=1; i<=mv; i++)
259        other[i] = 0; // reset (this is necessary, because some entries may not be updated by call to leadDeg)
260      other = leadDeg(Dp,other);
261
262      if( other==0 ) // early termination
263      {
264        // Dp is in coeff domain
265        CanonicalForm inv;
266        tryInvert(Dp,M,inv,fail); // check if zero-divisor
267        if(fail)
268          continue;
269        return CanonicalForm(1);
270      }
271
272      if( isLess(bound, other, 1, mv) ) // current prime unlucky
273        continue;
274
275      if( isLess(other, bound, 1, mv) ) // all previous primes unlucky
276      {
277        q = p;
278        D = mapinto(Dp); // shortcut CRA
279        for(int i=1; i<=mv; i++) // tighten bound
280          bound[i] = other[i];
281        continue;
282      }
283      chineseRemainder( D, q, mapinto(Dp), p, newD, newq );
284      // newD = Dp mod p
285      // newD = D mod q
286      // newq = p*q
287      q = newq;
288      if( D != newD )
289      {
290        D = newD;
291        continue;
292      }
293      On( SW_RATIONAL );
294      tmp = Farey( D, q );
295      if( fdivides( tmp, f ) && fdivides( tmp, g )) // trial division
296      {
297        Off( SW_RATIONAL );
298        return tmp;
299      }
300      Off( SW_RATIONAL );
301    }
302  }
303  // hopefully, we never reach this point
304  Off( SW_USE_QGCD );
305  D = gcd( F, G );
306  On( SW_USE_QGCD );
307  return D;
308}
309
310void tryBrownGCD( const CanonicalForm & F, const CanonicalForm & G, const CanonicalForm & M, CanonicalForm & result, bool & fail )
311{// assume F,G are multivariate polys over Z/p(a) for big prime p, M "univariate" polynomial in an algebraic variable
312  printf("Brown ");
313  if(F.isZero())
314  {
315    if(G.isZero())
316    {
317      result = G; // G is zero
318      return;
319    }
320    if(G.inCoeffDomain())
321    {
322      tryInvert(G,M,result,fail);
323      return;
324    }
325    // try to make G monic modulo M
326    CanonicalForm inv;
327    tryInvert(Lc(G),M,inv,fail);
328    if(fail)
329      return;
330    result = inv*G;
331    return;
332  }
333  if(G.isZero()) // F is non-zero
334  {
335    if(F.inCoeffDomain())
336    {
337      tryInvert(F,M,result,fail);
338      return;
339    }
340    // try to make F monic modulo M
341    CanonicalForm inv;
342    tryInvert(Lc(F),M,inv,fail);
343    if(fail)
344      return;
345    result = inv*F;
346    return;
347  }
348  if(F.inCoeffDomain())
349  {
350    tryInvert(F,M,result,fail);
351    return;
352  }
353  if(G.inCoeffDomain())
354  {
355    tryInvert(G,M,result,fail);
356    return;
357  }
358  CFMap MM,NN;
359  CFArray ps(1,2);
360  ps[1] = F;
361  ps[2] = G;
362  compress(ps,MM,NN); // maps MM, NN are created
363  CanonicalForm f=MM(F);
364  CanonicalForm g=MM(G);
365  // here: f, g are compressed
366  // compute largest variable in f or g (least one is Variable(1))
367  int mv = f.level();
368  if(g.level() > mv)
369    mv = g.level();
370  // here: mv is level of the largest variable in f, g
371  if(mv == 1) // f,g univariate
372  {
373    tryEuclid(f,g,M,result,fail);
374    if(fail)
375      return;
376    result = NN(result); // do not forget to map back
377    return;
378  }
379  // here: mv > 1
380  CanonicalForm cf = vcontent(f, Variable(2)); // cf is univariate poly in var(1)
381  CanonicalForm cg = vcontent(g, Variable(2));
382  CanonicalForm c;
383  tryEuclid(cf,cg,M,c,fail);
384  if(fail)
385    return;
386  f/=cf;
387  g/=cg;
388  if(f.inCoeffDomain())
389  {
390    tryInvert(f,M,result,fail);
391    if(fail)
392      return;
393    result = NN(result);
394    return;
395  }
396  if(g.inCoeffDomain())
397  {
398    tryInvert(g,M,result,fail);
399    if(fail)
400      return;
401    result = NN(result);
402    return;
403  }
404  int *L = new int[mv+1]; // L is addressed by i from 2 to mv
405  int *N = new int[mv+1];
406  for(int i=2; i<=mv; i++)
407    L[i] = N[i] = 0;
408  L = leadDeg(f, L);
409  N = leadDeg(g, N);
410  CanonicalForm gamma;
411  tryEuclid( firstLC(f), firstLC(g), M, gamma, fail );
412  if(fail)
413    return;
414  for(int i=2; i<=mv; i++) // entry at i=1 is not visited
415    if(N[i] < L[i])
416      L[i] = N[i];
417  // L is now upper bound for degrees of gcd
418  int *dg_im = new int[mv+1]; // for the degree vector of the image we don't need any entry at i=1
419  for(int i=2; i<=mv; i++)
420    dg_im[i] = 0; // initialize
421  CanonicalForm gamma_image, m=1;
422  CanonicalForm gm=0;
423  CanonicalForm g_image, alpha, gnew, mnew;
424  FFGenerator gen = FFGenerator();
425  for(FFGenerator gen = FFGenerator(); gen.hasItems(); gen.next())
426  {
427    alpha = gen.item();
428    gamma_image = gamma(alpha, Variable(1)); // plug in alpha for var(1)
429    if(gamma_image.isZero()) // skip lc-bad points var(1)-alpha
430      continue;
431    tryBrownGCD( f(alpha, Variable(1)), g(alpha, Variable(1)), M, g_image, fail ); // recursive call with one var less
432    if(fail)
433      return;
434    if(g_image.inCoeffDomain()) // early termination
435    {
436      tryInvert(g_image,M,result,fail);
437      if(fail)
438        return;
439      result = NN(c);
440      return;
441    }
442    for(int i=2; i<=mv; i++)
443      dg_im[i] = 0; // reset (this is necessary, because some entries may not be updated by call to leadDeg)
444    dg_im = leadDeg(g_image, dg_im); // dg_im cannot be NIL-pointer
445    if(isEqual(dg_im, L, 2, mv))
446    {
447      g_image /= lc(g_image); // make g_image monic over Z/p
448      g_image *= gamma_image; // multiply by multiple of image lc(gcd)
449      tryCRA( g_image, Variable(1)-alpha, gm, m, gnew, mnew, fail );
450      // gnew = gm mod m
451      // gnew = g_image mod var(1)-alpha
452      // mnew = m * (var(1)-alpha)
453      if(fail)
454        return;
455      m = mnew;
456      if(gnew == gm) // gnew did not change
457      {
458        g_image = gm / vcontent(gm, Variable(2));
459        if(fdivides(g_image,f) && fdivides(g_image,g)) // trial division
460        {
461          result = NN(c*g_image);
462          return;
463        }
464      }
465      gm = gnew;
466      continue;
467    }
468
469    if(isLess(L, dg_im, 2, mv)) // dg_im > L --> current point unlucky
470      continue;
471
472    if(isLess(dg_im, L, 2, mv)) // dg_im < L --> all previous points were unlucky
473    {
474      m = CanonicalForm(1); // reset
475      gm = 0; // reset
476      for(int i=2; i<=mv; i++) // tighten bound
477        L[i] = dg_im[i];
478    }
479  }
480  // we are out of evaluation points
481  fail = true;
482}
483
484
485void tryCRA( const CanonicalForm & x1, const CanonicalForm & q1, const CanonicalForm & x2, const CanonicalForm & q2, CanonicalForm & xnew, CanonicalForm & qnew, bool & fail )
486{ // polys of level <= 1 are considered coefficients. q1,q2 are assumed to be coprime
487  // xnew = x1 mod q1 (coefficientwise in the above sense)
488  // xnew = x2 mod q2
489  // qnew = q1*q2
490  CanonicalForm tmp;
491  if(x1.level() <= 1 && x2.level() <= 1) // base case
492  {
493    tryExtgcd(q1,q2,tmp,xnew,qnew,fail);
494    if(fail)
495      return;
496    xnew = x1 + (x2-x1) * xnew * q1;
497    qnew = q1*q2;
498    xnew = mod(xnew,qnew);
499    return;
500  }
501  CanonicalForm tmp2;
502  xnew = 0;
503  qnew = q1 * q2;
504  // here: x1.level() > 1 || x2.level() > 1
505  if(x1.level() > x2.level())
506  {
507    for(CFIterator i=x1; i.hasTerms(); i++)
508    {
509      if(i.exp() == 0) // const. term
510      {
511        tryCRA(i.coeff(),q1,x2,q2,tmp,tmp2,fail);
512        if(fail)
513          return;
514        xnew += tmp;
515      }
516      else
517      {
518        tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
519        if(fail)
520          return;
521        xnew += tmp * power(x1.mvar(),i.exp());
522      }
523    }
524    return;
525  }
526  // here: x1.level() <= x2.level() && ( x1.level() > 1 || x2.level() > 1 )
527  if(x2.level() > x1.level())
528  {
529    for(CFIterator j=x2; j.hasTerms(); j++)
530    {
531      if(j.exp() == 0) // const. term
532      {
533        tryCRA(x1,q1,j.coeff(),q2,tmp,tmp2,fail);
534        if(fail)
535          return;
536        xnew += tmp;
537      }
538      else
539      {
540        tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
541        if(fail)
542          return;
543        xnew += tmp * power(x2.mvar(),j.exp());
544      }
545    }
546    return;
547  }
548  // here: x1.level() == x2.level() && x1.level() > 1 && x2.level() > 1
549  CFIterator i = x1;
550  CFIterator j = x2;
551  while(i.hasTerms() || j.hasTerms())
552  {
553    if(i.hasTerms())
554    {
555      if(j.hasTerms())
556      {
557        if(i.exp() == j.exp())
558        {
559          tryCRA(i.coeff(),q1,j.coeff(),q2,tmp,tmp2,fail);
560          if(fail)
561            return;
562          xnew += tmp * power(x1.mvar(),i.exp());
563          i++; j++;
564        }
565        else
566        {
567          if(i.exp() < j.exp())
568          {
569            tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
570            if(fail)
571              return;
572            xnew += tmp * power(x1.mvar(),i.exp());
573            i++;
574          }
575          else // i.exp() > j.exp()
576          {
577            tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
578            if(fail)
579              return;
580            xnew += tmp * power(x1.mvar(),j.exp());
581            j++;
582          }
583        }
584      }
585      else // j is out of terms
586      {
587        tryCRA(i.coeff(),q1,0,q2,tmp,tmp2,fail);
588        if(fail)
589          return;
590        xnew += tmp * power(x1.mvar(),i.exp());
591        i++;
592      }
593    }
594    else // i is out of terms
595    {
596      tryCRA(0,q1,j.coeff(),q2,tmp,tmp2,fail);
597      if(fail)
598        return;
599      xnew += tmp * power(x1.mvar(),j.exp());
600      j++;
601    }
602  }
603}
604
605
606void tryExtgcd( const CanonicalForm & F, const CanonicalForm & G, CanonicalForm & result, CanonicalForm & s, CanonicalForm & t, bool & fail )
607{
608  // F, G are univariate polynomials (i.e. they have exactly one polynomial variable)
609  // F and G must have the same level AND level > 0
610  // we try to calculate gcd(f,g) = s*F + t*G
611  // if a zero divisor is encontered, 'fail' is set to one
612  Variable a, b;
613  if( !hasFirstAlgVar(F,a) && !hasFirstAlgVar(G,b) ) // note lazy evaluation
614  {
615    result = extgcd( F, G, s, t ); // no zero divisors possible
616    return;
617  }
618  if( b.level() > a.level() )
619    a = b;
620  // here: a is the biggest alg. var in F and G
621  CanonicalForm M = getMipo(a);
622  CanonicalForm P;
623  if( degree(F) > degree(G) )
624  {
625    P=F; result=G; s=0; t=1;
626  }
627  else
628  {
629    P=G; result=F; s=1; t=0;
630  }
631  CanonicalForm inv, rem, q, u, v;
632  // here: degree(P) >= degree(result)
633  while(true)
634  {
635    tryInvert( Lc(result), M, inv, fail );
636    if(fail)
637      return;
638    // here: Lc(result) is invertible modulo M
639    q = Lc(P)*inv * power( P.mvar(), degree(P)-degree(result) );
640    rem = P - q*result;
641    // here: s*F + t*G = result
642    if( rem.isZero() )
643    {
644      s*=inv;
645      t*=inv;
646      result *= inv; // monify result
647      return;
648    }
649    P=result;
650    result=rem;
651    rem=u-q*s;
652    u=s;
653    s=rem;
654    rem=v-q*t;
655    v=t;
656    t=rem;
657  }
658}
Note: See TracBrowser for help on using the repository browser.