source: git/factory/cf_gcd_charp.cc @ 7e96fe

fieker-DuValspielwiese
Last change on this file since 7e96fe was 4dfcb1, checked in by Hans Schönemann <hannes@…>, 16 years ago
*hannes: cstdio git-svn-id: file:///usr/local/Singular/svn/trunk@11012 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 17.0 KB
Line 
1#include "config.h"
2#ifdef HAVE_CSTDIO
3#include <cstdio>
4#else
5#include <stdio.h>
6#endif
7#ifndef NOSTREAMIO
8#ifdef HAVE_IOSTREAM
9#include <iostream>
10#define ISTREAM std::istream
11#define OSTREAM std::ostream
12#define CERR std::cerr
13#elif defined(HAVE_IOSTREAM_H)
14#include <iostream.h>
15#define ISTREAM istream
16#define OSTREAM ostream
17#define CERR cerr
18#endif
19#endif
20#include <math.h>
21#include <cf_factory.h>
22#include <variable.h>
23#include <canonicalform.h>
24#include <cf_iter.h>
25#include <cf_random.h>
26#include <cf_algorithm.h>
27#include <cf_map.h>
28
29static CanonicalForm contentWRT(const CanonicalForm & F, const int lev);
30static int degWRT(CanonicalForm F, const int lev);
31static CanonicalForm lcoefWRT( const CanonicalForm & F, const int lev);
32static CanonicalForm newtonInterp(CFList &alpha, CFList &u, const Variable & x);
33static CanonicalForm simpleGCD(const CanonicalForm & A, const CanonicalForm & B);
34CanonicalForm newGCD(CanonicalForm A, CanonicalForm B);
35static CanonicalForm GFPowDown(const CanonicalForm & A, int k);
36static CanonicalForm GFPowUp(const CanonicalForm & A, int k);
37static CanonicalForm GFMapUp(const CanonicalForm & A, int k);
38static CanonicalForm GFMapDown(const CanonicalForm & A, int k);
39
40
41
42
43static CanonicalForm
44contentWRT0(const CanonicalForm & F, const int lev, const int lev0)
45// Computes the content of a polynomial, considering the variables of level
46// larger than lev as as parameters.
47{
48  if(F.inBaseDomain() || (F.mvar().level() <= lev))
49  {
50    return(1);
51  }
52  else
53  {
54    if (F.isUnivariate())
55    {
56      return(F);
57    }
58    else
59    {
60      CanonicalForm pol;
61      CFIterator i = CFIterator(F);
62      CanonicalForm c = 0;
63      for(; i.hasTerms(); i++)
64      {
65        CanonicalForm cc=i.coeff();
66        if (cc.level() > lev0) 
67          pol = contentWRT0(cc, lev, lev0-1 );
68        else
69          pol = contentWRT(cc, lev -1);
70        c = gcd(c, pol);
71        if(c.isOne())
72        {
73          return c;
74        }
75      }
76      return c;
77    }
78  }
79}
80
81static CanonicalForm
82contentWRT(const CanonicalForm & F, const int lev)
83// Computes the content of a polynomial, considering the variables of level
84// larger than lev as as parameters.
85{
86  //if (lev <0)
87  //  cout << "contentWRT:" <<F << " " << lev <<"\n";//printf("level=%d\n",lev);
88  //int debug = 0;
89  //if(debug == 1)cout << "contentWRT input - F:  " << F << " lev: " << lev << endl;
90  if(F.inBaseDomain() || (F.mvar().level() <= lev))
91  {
92    //if(debug == 1)cout << "output 1:" << F << endl;
93    return(1);
94  }
95  else
96  {
97    if (F.isUnivariate())
98    {
99      //if(debug == 1)cout << "output 2:" << F << endl;
100      return(F);
101    }
102    else
103    {
104      CanonicalForm pol;
105      CFIterator i = CFIterator(F);
106      CanonicalForm c = 0;
107      for(; i.hasTerms(); i++)
108      {
109        CanonicalForm cc=i.coeff();
110        if (cc.level() > lev) 
111          pol = contentWRT0(cc, lev, cc.level());
112        else
113          pol = contentWRT(i.coeff(), lev - 1);
114        //if(debug == 1)cout << "c: " << c << " - pol : " << pol << endl;
115        c = gcd(c, pol);
116        //if(debug == 1)cout << "c temp:" << c << endl;
117        if(c.isOne())
118        {
119          //if(debug == 1)cout << "output 3:" << c << endl;
120          return c;
121        }
122      }
123      //if(debug == 1)cout << "output 4:" << c << endl;
124      return c;
125    }
126  }
127}
128
129// Degree of F wrt all variables of level smaller than or equal to lev
130static int degWRT(CanonicalForm F, const int lev)
131{
132  int deg = F.degree(lev);
133  for(int i = lev; i >= 1; i--)
134  {
135    F = F.LC(i);
136    deg = deg + F.degree(i - 1);
137  }
138  return deg;
139}
140
141// Leading coefficient of F wrt all variables of level smaller than or equal to lev.
142static CanonicalForm lcoefWRT(const CanonicalForm & F, const int lev)
143{
144  CanonicalForm FL;
145  FL = F;
146
147  for(int i = lev; i >= 1; i--)
148  {
149    FL = FL.LC(i);
150  }
151  return FL;
152}
153
154
155static CanonicalForm
156newtonInterp(const CanonicalForm alpha, const CanonicalForm u, const CanonicalForm newtonPoly, const CanonicalForm oldInterPoly, const Variable & x)
157// Newton interpolation - Incremental algorithm.
158// Given a list of values alpha_i and a list of polynomials u_i, 1 <= i <= n,
159// computes the interpolation polynomial assuming that
160// the polynomials in u are the results of evaluating the variabe x
161// of the unknown polynomial at the alpha values.
162// This incremental version receives only the values of alpha_n and u_n and
163// the previous interpolation polynomial for points 1 <= i <= n-1, and computes
164// the polynomial interpolating in all the points.
165// newtonPoly must be equal to (x - alpha_1) * ... * (x - alpha_{n-1})
166{
167  /*
168  int debug = 0;
169  if(debug)
170  {
171    cout << "newtonInterpIncremental input - variable " << x <<endl;
172    cout << "newtonInterpIncremental input - alpha:" << alpha << " - u: " << u << endl;
173    cout << "newtonInterpIncremental input - newtonPoly: " << newtonPoly << " - oldInterPoly: " << oldInterPoly << endl;
174  }
175  */
176
177  CanonicalForm interPoly;
178
179  interPoly = oldInterPoly + (u - oldInterPoly(alpha, x)) / newtonPoly(alpha, x) * newtonPoly;
180
181  //if(debug)cout << "newtonInterpIncremental output:" << interPoly << endl;
182  return interPoly;
183}
184
185
186// Univariate GCD
187// Naive implementation of Euclidean Algorithm.
188// Should be used only for GCD of univariate polys over finite fields,
189// where there is no coefficient growth.
190static CanonicalForm simpleGCD(const CanonicalForm & A, const CanonicalForm & B)
191{
192  //int debug = 0;
193  CanonicalForm P1, P2;
194  /*
195  if(debug == 1)
196  {
197    cout << "simpleGCD input" << endl;
198    cout << "A: " << A << endl;
199    cout << "B: " << B << endl;
200  }
201  */
202  if (A.degree() > B.degree())
203  {
204    P1 = A;
205    P2 = B;
206  }
207  else
208  {
209    P1 = B;
210    P2 = A;
211  }
212  CanonicalForm rem;
213  while(!P2.isZero())
214  {
215    // cout << "P1: " << P1 << " - P2: " << P2 << endl;
216    rem = P1 % P2;
217    // cout << "rem: " << rem << endl;
218    P1 = P2;
219    P2 = rem;
220  }
221  //if(debug == 1)cout << "simpleGCD output: " << P1 << endl;
222  return(P1);
223}
224
225
226static CanonicalForm GFPowDown(const CanonicalForm & A, int k)
227// Replaces all coefficients of A in the ground field by their k-th roots.
228// It assumes that the k-th roots exist.
229// This procedure is used to map down a polynomial from an extension field.
230{
231  CanonicalForm result = 0;
232  int i, j;
233  int fieldSize = pow(getCharacteristic(), getGFDegree());
234  CanonicalForm g;
235  for(i = 0; i <= degree(A); i++)
236  {
237    if(!A[i].isZero())
238    {
239      //cout << "i: " << i << endl;
240      //cout << "A[i]: " << A[i] << endl;
241      if(A[i].inBaseDomain())
242      {
243        //cout << "GFPowDown - inBaseDomain" << endl;
244        g = getGFGenerator();
245        j = 0;
246        while(((power(g, j * k)*1) != (A[i]*1)) && (j <= fieldSize))
247        {
248          //cout << "power(g, j * k)*1: " << power(g, j * k)*1 << " - A[i]*1: " << A[i]*1 << endl;
249          j++;
250        }
251        if(j == fieldSize + 1)  return(-1);
252        result = result + power(g, j) * power(A.mvar(), i);
253        //cout << "power(A[i], k): " << power(A[i], k) << endl;
254        //cout << "result: " << result << endl;
255      }
256      else
257      {
258        //cout << "not inBaseDomain" << endl;
259        result = result + GFPowDown(A[i], k) * power(A.mvar(), i);;
260        // power(pol[i], k) * power(A.mvar(), i);
261        //pol[i] = GFMap(pol[i], k);
262      }
263    }
264  }
265  return(result);
266}
267
268static CanonicalForm GFPowUp(const CanonicalForm & A, int k)
269// Raises all coefficients of A in the ground field to the power k.
270// Used for maping a polynomial to an extension field.
271{
272  //cout << "A:" << A <<"\n";
273  CanonicalForm result = 0;
274  int i;
275  for(i = 0; i <= degree(A); i++)
276  {
277    if(!A[i].isZero())
278    {
279      //cout << "i: " << i << endl;
280      //cout << "A[i]: " << A[i] << endl;
281      if(A[i].inBaseDomain())
282      {
283        //cout << "inBaseDomain" << endl;
284        result = result + power(A[i], k) * power(A.mvar(), i);
285        //cout << "power(A[i], k): " << power(A[i], k) << endl;
286        //cout << "result: " << result << endl;
287      }
288      else
289      {
290        //cout << "not inBaseDomain" << endl;
291        result = result + GFPowUp(A[i], k) * power(A.mvar(), i);;
292      }
293    }
294  }
295  //cout << "result:" << result <<"\n";
296  return(result);
297}
298
299CanonicalForm GFMapUp(const CanonicalForm & A, int k)
300// Maps all coefficients of A to the base domain, asumming A is in GF(p^k).
301// The current base domain must be GF(p^j), with j a multiple of k.
302{
303  int p = getCharacteristic();
304  int expon = getGFDegree();
305  int extExp = expon / k;
306    // Assumes that we are using Conway polynomials
307  return(GFPowUp(A, extExp));
308}
309
310CanonicalForm GFMapDown(const CanonicalForm & A, int k)
311// Maps all coefficients of A from the base domain to GF(p^k).
312// The current base domain must be GF(p^j), with j a multiple of k.
313{
314  int p = getCharacteristic();
315  int expon = getGFDegree();
316  //cout << "Expon: " << expon << endl;
317  int extExp = expon / k;
318    // Assumes that we are using Conway polynomials
319  return(GFPowDown(A, extExp));
320}
321
322CanonicalForm newGCD(CanonicalForm A, CanonicalForm B)
323// Computes the GCD of two polynomials over a prime field.
324// Based on Algorithm 7.2 from "Algorithms for Computer Algebra"
325{
326  //int debug = 1;
327  //if(debug)
328  //{
329  //  cout << "newGCD input" << endl;
330  //  cout << "A: " << A << endl;
331  //  cout << "B: " << B << endl;
332  //}
333
334  if(A*1 == 0)
335  {
336    //if(debug)cout << "A Zero!" << endl;
337    return(abs(B));
338  }
339  if(B*1 == 0)
340  {
341    //if(debug)cout << "B Zero!" << endl;
342    return(abs(A));
343  }
344  if (A.inBaseDomain()) return A.genOne();
345  if (B.inBaseDomain()) return B.genOne();
346
347  CanonicalForm pol;
348  int p = getCharacteristic();
349  int k = 1;
350  int fieldSize = p;
351  if (CFFactory::gettype() == GaloisFieldDomain)
352  {
353    k=getGFDegree();
354    fieldSize = pow(p, k);
355  }
356
357  //if(debug)
358  //{
359  //  cout << "p: " << p << endl;
360  //  cout << "k: " << k << endl;
361  //  cout << "fieldSize: " << fieldSize << endl;
362  //  cout << "pow: " << pow(p, k) << endl;
363  //}
364 
365  CFMap M,N;
366  compress(A,B,M,N);
367  A=M(A);
368  B=M(B);
369  // Compute the main variable (the largest in A and B)
370  Variable x = A.mvar();
371  int mv = x.level();
372  if(B.mvar().level() > mv)
373  {
374    x = B.mvar();
375    mv = x.level();
376  }
377  //cout << "main variable " << x << endl << endl;
378
379  // Checks for univariate polynomial
380  if ( mv == 1 )
381  {
382    // This call can be replaced by a faster GCD algorithm
383    pol = simpleGCD(A, B); // Univariate GCD
384    //cout << "newGCD output 1: " << pol << endl;
385    return N(pol);
386  }
387
388  CanonicalForm b;
389  CFArray bArray(0, fieldSize-1);    // Stores the bs already used
390  int sizebArray;
391
392  GFRandom genGF;
393  FFRandom genFF;
394  int i, j;
395  int used;
396
397  CanonicalForm c;    // gcd of the contents
398  CanonicalForm C;
399  CanonicalForm Cb;    // gcd of Ab and Bb
400  CanonicalForm H = 0;      // for Newton Interpolation
401  CanonicalForm newtonPoly = 1;  // for Newton Interpolation
402  CanonicalForm Cblc;
403
404  // Contents and primparts of A and B
405  CanonicalForm contA, contB;    // Contents of A and B
406  CanonicalForm Ap, Bp;    // primpart of A and B
407  contA = contentWRT(A, mv - 1);
408  contB = contentWRT(B, mv - 1);
409  c = simpleGCD(contA, contB);    // gcd of univariate polynomials
410  Ap = A / contA;
411  Bp = B / contB;
412
413  CanonicalForm AL, BL;  // leading coefficients of A and B
414  CanonicalForm g;    // gcd of AL and BL
415  AL = lcoefWRT(Ap, mv - 1);
416  BL = lcoefWRT(Bp, mv - 1);
417  g = simpleGCD(AL, BL);    // gcd of univariate polynomials
418
419  CanonicalForm Ab, Bb, gb;  // A, B and g evaluated at b
420
421  int m;          // degree of the gcd of Ab and Bb
422  int n = degWRT(Ap, mv - 1);
423  if(degWRT(Bp, mv - 1) < n)
424  {
425    n = degWRT(Bp, mv - 1);
426  }
427
428  int fail = 0;
429  int goodb;
430  // The main loop
431  //cout << "start loop\n";
432  sizebArray = 0;
433  do
434  {
435    // Searches for a good b.
436    // If there are no more possible b, the algorithm fails.
437    goodb = 0;
438    if(sizebArray >= fieldSize-1)
439    {
440      // An extension field is needed.
441      fail = 1;
442    }
443    else
444    {
445      do
446      {
447        // Searches for a new element of the ground field
448        do
449        {
450          // New element of the ground field
451          if(k > 1)
452          {
453            b = genGF.generate();
454          }
455          else
456          {
457            b = genFF.generate();
458          }
459          //cout << "try(" << sizebArray << "):" << b;
460          // Checks if this element was already used
461          used = 0;
462          for(i = 0; i < sizebArray; i++)
463          {
464            // Multiplication by 1 is used to prevent a bug which
465            // produces b=a^(q-1) as a random element.
466            if((bArray[i]*1) == (b*1))
467            {
468              used = 1;
469              //cout << " used\n";
470            }
471          }
472          //if(debug==1)cout << "b: " << b << endl;
473        }
474        while(used == 1);
475        bArray[sizebArray] = b;
476        sizebArray++;
477        // b must not cancel the gcd of the leading coefficients
478        if(g(b, mv) != 0)
479        {
480          goodb = 1;
481          //  cout << " good\n";
482        }
483        else
484        {
485          //  cout << " bad";
486          if(sizebArray == fieldSize - 1)
487          {
488            fail = 1;
489            //cout << " out of elems " << sizebArray << "tried";
490          }
491          //cout << "\n";
492        }
493      }
494      while((goodb == 0) && (fail == 0));
495    }
496    if(fail)
497    {
498      // Algorithm fails. An extension is needed.
499
500      // Computes the exponent of the ring extension so as to have enough interpolation points.
501      int degMax;
502      if(totaldegree(A) > totaldegree(B))
503      {
504        degMax = totaldegree(A);
505      }
506      else
507      {
508        degMax = totaldegree(B);
509      }
510      int expon = 2; // expon <= will not extend the field
511      while(pow(fieldSize, expon) < degMax)
512      {
513        expon++;
514      }
515      //if(debug)cout << "Not enough elements in the base field. An extension to " << p << "^" << k*expon << " is needed." << endl;
516      if(k > 1)
517      {
518        if(pow(p,k * expon) < (1<<16))
519        {
520          setCharacteristic(p, k * expon, 'b');
521          CanonicalForm P1 = GFMapUp(A, k);
522          CanonicalForm P2 = GFMapUp(B, k);
523          //cout << "newGCD(mapped):" << P1 << " , " << P2 <<"\n";
524          pol = newGCD(P1, P2);
525          pol = GFMapDown(pol, k);
526          setCharacteristic(p, k, 'a');
527          //if(debug)cout << "newGCD output 5: " << pol << endl;
528          CanonicalForm temp=N(pol);
529          temp/=temp.lc();
530          return temp;
531        }
532        else
533        {
534          Off(SW_USE_GCD_P);
535          CanonicalForm temp=N(gcd( A, B));
536          On(SW_USE_GCD_P);
537          return temp;
538        } 
539      }
540      else
541      {
542        if(pow(p,k * expon) < (1<<16))
543        {
544          setCharacteristic(p, k * expon, 'a');
545          CanonicalForm P1 = A.mapinto();
546          CanonicalForm P2 = B.mapinto();
547          pol = newGCD(P1, P2);
548          setCharacteristic(p);
549          //if(debug)cout << "newGCD output 4: " << pol << endl;
550          CanonicalForm temp=N(pol);
551          temp/=temp.lc();
552          return temp;
553        }
554        else
555        {
556          Off(SW_USE_GCD_P);
557          CanonicalForm temp=N(gcd( A, B));
558          On(SW_USE_GCD_P);
559          return temp;
560        } 
561      }
562    }
563    else
564    {
565      // Evaluate the polynomials in b
566      Ab = Ap(b, mv);
567      Bb = Bp(b, mv);
568      gb = g(b, mv);
569      Cb = newGCD(Ab, Bb);
570      //if(debug)cout << "newGCD received: " << Cb << endl;
571      m = Cb.degree();
572
573      Cblc = Cb.lc();
574      Cb *= gb;
575      Cb /= Cblc;
576      // Test for unlucky homomorphism
577      if(m < n)
578      {
579        // The degree decreased, we have to start it all over.
580        H = Cb;
581        newtonPoly = newtonPoly * (x - b);
582        n = m;
583      }
584      else if(m == n)
585      {
586        // Good b
587        H = newtonInterp(b, Cb, newtonPoly, H, x);
588        newtonPoly = newtonPoly * (x - b);
589        if(lcoefWRT(H, mv - 1) == g)
590        {
591          C = H / contentWRT(H, mv - 1);  // primpart
592          if(fdivides(C, A) && fdivides(C, B))
593          {
594            //if(debug)cout << "newGCD output 2: " << c * C<< endl;
595            return N(c * C);
596          }
597          else
598          {
599            if(m == 0)
600            {
601              //if(debug)cout << "newGCD output 3: " << c << endl;
602              return N(c);
603            }
604          }
605        }
606      }
607    }
608  } while(1);
609  //cout << "No way to get here!" << endl;
610  //cout << "H:" << H << endl;
611  // No way to get here!
612  return H;
613}
614
615#if 0
616main()
617{
618  CanonicalForm A;
619  CanonicalForm B;
620  CanonicalForm pol;
621  Variable x('x'), y('y'), z('z');
622
623  cout << "setCharacteristic(2, 4, 'a')" << endl;
624  setCharacteristic(2, 4, 'a');
625
626  int k = getGFDegree();
627  int p = getCharacteristic();
628  int fieldSize = pow(p, k);
629  cout << "p: " << p << endl;
630  cout << "GFDegree: " << k << endl;
631  cout << "fieldSize: " << fieldSize << endl << endl;
632
633  CanonicalForm g = getGFGenerator();
634  //CanonicalForm g = 1;
635  A = power((x*y*y-power(x, 7)), 42) * power((power(y, 5) + g*y*y*power(x,13) + g*g), 13);
636  B = power((x+y+1), 37) * power((power(y, 5) + g*y*y*power(x,13) + g*g), 13);
637  cout << "A: " << A << endl;
638  cout << "B: " << B << endl << endl;
639
640  int i;
641  CanonicalForm qa;
642  CanonicalForm lco;
643
644  for(i = 1; i <= 1; i++){
645    pol = newGCD(A * i, B * i);
646    lco = pol.lc();
647    cout << "new GCD: " << (pol / lco) << endl;
648  }
649
650  for(i = 1; i<=1; i++){
651    pol = gcd(A*i, B*i);
652    lco = pol.lc();
653    cout << "old GCD: " << pol / lco << endl;
654  }
655
656}
657#endif
658
Note: See TracBrowser for help on using the repository browser.