source: git/factory/cf_gcd_charp.cc @ 16466a

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