Sindbad~EG File Manager
/* 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