source: git/factory/cf_gcd_charp.cc @ fa7ed7

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