Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/polyval/
Upload File :
Current File : /usr/home/beeson/MathXpert/polyval/MODPOLY.C

/* Polynomial arithmetic mod p */
/* done with p an unsigned long  for speed */
/* M. Beeson, 1.20.93 */
/* 9.23.97 last modified */
/* This file is not actually used in MathXpert */

#include "terms.h"
#include "polynoms.h"
#include "modp.h"
static int polymod cantor_zassenhaus(modpoly u, int d, modpoly *ans);

/*__________________________________________________________________*/
/* The prime in question is a static global.  Here are the
access functions. */

static unsigned long Prime;

unsigned long get_modulus(void)
{ return Prime;
}

void set_modulus(unsigned long p)
{ Prime = p;
}

/*____________________________________________________________________*/

modpoly make_modpoly(int m)
/* Make a polynomial of degree m by allocating space for the coefficients */
{  modpoly p;
   p.c = callocate(m + 1, sizeof(coef));
   if(p.c == NULL)
      { nospace();  /* handles out-of-space errors */
      }
   p.deg = m;
   return p;
}
/*_______________________________________________________________________*/
modpoly copy_modpoly(modpoly p)
/* make a fresh copy of p */
{  q = make_modpoly(p.deg);
   memcpy(q.c,p.c,p.deg+1);
   return q;
}
/*_____________________________________________________________*/
void destroy_modpoly(modpoly p)
{  free2(p.c);
}
/*______________________________________________________________*/
modpoly modpolyadd(modpoly u, modpoly v)
/* add two polynomials and return the result */
{ int i;
  int d = u.deg > v.deg ? u.deg : v.deg;
  modpoly ans = make_modpoly(d);
  for(i=0;i<=d;i++)
     ans.c[i] = addmod(u.c[i],v.c[i],Prime);
  while(ans.c[i] == 0)
     --d;
  ans.deg = d;
  return ans;
}

/*______________________________________________________________*/
modpoly modpolymult(modpoly u, modpoly v)
/* multiply two polynomials and return the result */
{ int i,j;
  int d = u.deg + v.deg;
  coef c;
  modpoly ans = make_modpoly(d);
  for(i=0;i<=d;i++)
     { c = 0;
       for(j= i>= v.deg ? i-v.deg : 0 ;j<=i && j<=u.deg;j++)
          c = addmod(c,mulmod(u.c[j],v.c[i-j]));
       ans.c[i] = c;
     }
  return ans;
}

/*______________________________________________________________*/
MEXPORT void EXPORT modpoly_scalarmult(coef c, modpoly u)
/* multiply each coefficient of u by c and return the result
in fresh space, leaving u unaltered */
{ modpoly ans = make_modpoly(u.deg);
  int i;
  for(i=0;i<u.deg;i++)
     ans.c[i] = modmult(c,u.c[i]);
  return ans;
}

/*______________________________________________________________*/

MEXPORT void EXPORT modpolydiv(modpoly u, modpoly v, modpoly *q, modpoly *r)
/* divide u by v returning quotient and remainder in q and r,
with coefficients in fresh space.  See Knuth volumen 2 page 402.
*/
{ int m = u.deg;
  int n = v.deg;
  int k;
  modpoly localu;
  coef c;
  if(m < n)
     { *r = copy_modpoly(u);
       *q = make_modpoly(0);
       q->c[0] = 0;  /*  *q is the zero polynomial */
       return;
     }
  *q = make_modpoly(m-n);
  localu = copy_modpoly(u);
  for(k=m-n;k>=0;k--)
     { q->c[k] = moddiv(localu.c[n+k],v.c[n]);
       for(j=n+k-1, j>=k;j--)
          localu.c[j] = addmod(localu.c[j], Prime-multmod(q.c[i], v.c[j-k],Prime),Prime);
     }
  for(i=localu.deg;i>=0;i--)
     { if(localu.c[i])
          break;
     }
  if(i<0)
     { /* zero remainder */
       destroy_modpoly(localu);
       *r = make_modpoly(0);
       r->c[0] = 0;
       return;
     }
  *r = make_modpoly(i);
     { for(j=0;j<=i;j++)
          r.c[j] = localu.c[j];
       destroy_modpoly(localu);
       return;
     }
}

/*______________________________________________________________*/
modpoly modpolygcd(modpoly uu, modpoly vv)
/* Euclidean algorithm for the gcd.
   Return the answer in fresh space.
*/
{ modpoly u,v,q,r;
  int i,n;
  if(vv.deg = 0 && vv.c[0] == 0)
     return copy_modpoly(uu);
  if(vv.deg > uu.deg)
     return modpolygcd(vv,uu);
  n = uu.deg;
  u = make_modpoly(n);
  v = make_modpoly(n);
  for(i=0;i<=uu.deg;i++)
     u.c[i] = uu.c[i];
  for(i=0;i<=vv.deg;i++)
     v.c[i] = vv.c[i];
  while(v.deg > 0 || v.c[0] != 0)
     { modpolydiv(u,v,&q,&r);
       destroy_modpoly(q);
       u.deg = v.deg;
       for(i=0;i<=v.deg;i++)
          u.c[i] = v.c[i];
       for(i=0;i<=r.deg;i++)
          v.c[i] = r.c[i];
       destroy_modpoly(r);
     }
  ans = make_modpoly(u.deg);
  for(i=0;i<=u.deg;i++)
     ans.c[i] = u.c[i];
  destroy_modpoly(u);
  destroy_modpoly(v);
  return ans;
}
/*__________________________________________________________________*/
MEXPORT static unsigned modpoly EXPORT modpolyexp(modpoly u,unsigned long m, modpoly v)
/* compute u^m mod v in the field with coeffiecients mod Prime. */
{ modpoly s,t,ans;
  int i,k;
  if(m==0)
     return 1;
  if(m==1)
     { polydiv(u,v,&q,&ans);
       destroy_modpoly(q);
       return ans;
     }
  k = 0;
  while( m>>k )
     k++;    /* makes k the bitlength of m */
  t=make_modpoly(0);
  t.c[0] = 1;
  for(i=k-1;i>=0;i--)
    { s = multmodpoly(t,t,Prime);
      destroy_modpoly(t);
      polydiv(s,v,&q,&r);
      t = r;
      destroy_modpoly(q);
      destroy_modpoly(s);
      if((m>>i) & 1)
         { s = multmodpoly(t,u,Prime);
           destroy_modpoly(t);
           polydiv(t,v,&q,&r);
           destroy_modpoly(t);
           t = r;
           destroy_modpoly(q);
         }
    }
  return t;
}

/*______________________________________________________________*/
static int modpolyfactor(modpoly u, modpoly *ans, int *dim, int *powers)
/* ans is passed as an array of dimension at least u.deg; at exit,
dim is the number of factors of u
ans[0]...ans[dim-1] contain the factors.
powers[0]...powers[dim-1] contain the exponents of those factors.

The algorithm is probabilistic so return value 0
indicates success, 1 indicates failure on repeated trials (very unlikely);
2 indicates failure because Prime^d overflows an unsigned long.

It is NOT assumed that u is squarefree.
*/

/* Algorithm:  page 430 Knuth volume 2 */

{ modpoly x,v,w,gd,t,zz;
  unsigned k=0;
  unsigned k1;
  int j;
  d = 0;
  v = modpoly_copy(u);
  x = make_modpoly(1);
  x.c[0] = 0;
  x.c[1] = 1;
  w = copy_modpoly(x);
  while( (d<<1) + 2 <= v.deg)
     { ++d;
       w2 = modpolyexp(w,Prime,v); /* w2 = w^Prime mod v */
       destroy_modpoly(w);
       w = w2;
       t = copy_modpoly(w);
       t.c[1] = t.c[1] > 0 ? t.c[1]-1 : Prime -1;   /* t = w-x          */
       gd = modpolygcd(t,v);                        /* gd = gcd(w-x,v)  */
       destroy_modpoly(t);

       /* gd is divisible by every irreducible factor of u
          which has degree d.  If u were squarefree, it would
          be the product of all such factors; as it is, it contains
          just one power of each irreducible factor of degree d,
          since w-x is squarefree (see Note to exercise 36, p. 632
          of Knuth volume 2). */
       k1 = k;
       if(gd.deg)
          { while(gd.deg > d)
              { err = cantor_zassenhaus(gd,d,ans+k);
                if(err)
                   return err;
                modpolydiv(gd,ans[k],&q,&r);
                powers[k] = 1;

                assert(r.deg == 0 && r.c[0] == 0);
                destroy_modpoly(r);
                destroy_modpoly(gd);
                gd = q;
                ++k;
              }
            ans[k] = gd;
            ++k;
          }
       modpolydiv(v,gd,&q,&r);
       destroy_modpoly(v);
       v = q;   /* v = v/gd          */
       /* Now, if u was not squarefree, there may be more
          powers of ans[k1],...,ans[k-1] to remove from
          v before going on. */
       for(j=k1;j<k;j++)
          { /* take out more factors of ans[j] */
            while(1)
               { modpolydiv(v,ans[j],&q,&r);
                 if(r.deg == 0 && r.c[0] == 0)
                     { ++powers[j];
                       destroy_modpoly(r);
                       destroy_modpoly(v);
                       v = q;
                     }
                 else
                    break;
               }
          }
       modpolydiv(w,v,&q,&r);
       destroy_modpoly(w);
       w = r;                                      /* w = w mod v       */
       destroy_modpoly(gd);
     }
  if(v.deg > 0 || v.c[0] != 0)
     { ans[k] = v;
       ++k;
     }
  *dim = k;
  return 0;
}
/*______________________________________________________________________*/
static int modpoly cantor_zassenhaus(modpoly u, int d, modpoly *ans)
/* u is assumed to be a nontrivial product of polynomials of degree d;
find a nontrivial factor of u and return it in *ans;
return 0 for success. This is a probabilistic algorithm so it
can theoretically fail, in which case the return value is 1.
In case Prime^d overflows an unsigned long, the return value is 2.
  This algorithm assumes Prime is odd.
*/

/* Algorithm: page 430 Knuth vol. 2 */

{ modpoly t = make_modpoly(3);
  int i;
  double checkit;
  unsigned long e;
  int d = u.deg;
  assert(u.deg > d);
  /* first try linear t */
  t.deg = 1;
  t.c[1] = 1;
  /* Prime ^ d must not overflow an unsigned long */
  checkit = pow(Prime,d);
  if(checkit > 2 * (double) MAXLONG)
     return 1;
  for(i=1;i<20 && i < Prime; i++)
     { t.c[0] = i;
       fastexp(Prime,d,&e);  /* does not test for overflow */
       q = modpolygcd(u, modpolyexp(t,e,u));
       if(q.deg)
          { *ans = q;
            return 0;
          }
     }
  /* Well, the first 20 linear t didn't work.  Let's try quadratic t */
  t.deg = 2;
  t.c[2] = 1;
  for(i=1;i<20 && i< polyp;i++)
     { t.c[1] = i;
       for(j=1;j<20 && j < polyp;j++)
         { t.c[0] = j;
           q = modpolygcd(u,modpolyexp(t,e,u));
           if(q.deg)
              { *ans = q;
                return q;
              }
         }
     }
  return 1;  /* failure */
}
/*___________________________________________________________________*/


Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists