?? lzz_px1.cpp
字號:
}
void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m)
{
long n = F.n;
if (m < 1 || m > n) Error("ProbMinPoly: bad args");
long i;
vec_zz_p R(INIT_SIZE, n);
for (i = 0; i < n; i++) random(R[i]);
DoMinPolyMod(h, g, F, m, R);
}
void MinPolyMod(zz_pX& hh, const zz_pX& g, const zz_pXModulus& F, long m)
{
zz_pX h, h1;
long n = F.n;
if (m < 1 || m > n) Error("MinPoly: bad args");
/* probabilistically compute min-poly */
ProbMinPolyMod(h, g, F, m);
if (deg(h) == m) { hh = h; return; }
CompMod(h1, h, g, F);
if (IsZero(h1)) { hh = h; return; }
/* not completely successful...must iterate */
long i;
zz_pX h2, h3;
zz_pXMultiplier H1;
vec_zz_p R(INIT_SIZE, n);
for (;;) {
R.SetLength(n);
for (i = 0; i < n; i++) random(R[i]);
build(H1, h1, F);
UpdateMap(R, R, H1, F);
DoMinPolyMod(h2, g, F, m-deg(h), R);
mul(h, h, h2);
if (deg(h) == m) { hh = h; return; }
CompMod(h3, h2, g, F);
MulMod(h1, h3, H1, F);
if (IsZero(h1)) { hh = h; return; }
}
}
void IrredPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m)
{
vec_zz_p R(INIT_SIZE, 1);
if (m < 1 || m > F.n) Error("IrredPoly: bad args");
set(R[0]);
DoMinPolyMod(h, g, F, m, R);
}
void diff(zz_pX& x, const zz_pX& a)
{
long n = deg(a);
long i;
if (n <= 0) {
clear(x);
return;
}
if (&x != &a)
x.rep.SetLength(n);
for (i = 0; i <= n-1; i++) {
mul(x.rep[i], a.rep[i+1], i+1);
}
if (&x == &a)
x.rep.SetLength(n);
x.normalize();
}
void MakeMonic(zz_pX& x)
{
if (IsZero(x))
return;
if (IsOne(LeadCoeff(x)))
return;
zz_p t;
inv(t, LeadCoeff(x));
mul(x, x, t);
}
void PlainMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n)
{
zz_pX y;
mul(y, a, b);
trunc(x, y, n);
}
void FFTMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n)
{
if (IsZero(a) || IsZero(b)) {
clear(x);
return;
}
long d = deg(a) + deg(b);
if (n > d + 1)
n = d + 1;
long k = NextPowerOfTwo(d + 1);
fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k);
TofftRep(R1, a, k);
TofftRep(R2, b, k);
mul(R1, R1, R2);
FromfftRep(x, R1, 0, n-1);
}
void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n)
{
if (n < 0) Error("MulTrunc: bad args");
if (deg(a) <= NTL_zz_pX_MUL_CROSSOVER || deg(b) <= NTL_zz_pX_MUL_CROSSOVER)
PlainMulTrunc(x, a, b, n);
else
FFTMulTrunc(x, a, b, n);
}
void PlainSqrTrunc(zz_pX& x, const zz_pX& a, long n)
{
zz_pX y;
sqr(y, a);
trunc(x, y, n);
}
void FFTSqrTrunc(zz_pX& x, const zz_pX& a, long n)
{
if (IsZero(a)) {
clear(x);
return;
}
long d = 2*deg(a);
if (n > d + 1)
n = d + 1;
long k = NextPowerOfTwo(d + 1);
fftRep R1(INIT_SIZE, k);
TofftRep(R1, a, k);
mul(R1, R1, R1);
FromfftRep(x, R1, 0, n-1);
}
void SqrTrunc(zz_pX& x, const zz_pX& a, long n)
{
if (n < 0) Error("SqrTrunc: bad args");
if (deg(a) <= NTL_zz_pX_MUL_CROSSOVER)
PlainSqrTrunc(x, a, n);
else
FFTSqrTrunc(x, a, n);
}
void FastTraceVec(vec_zz_p& S, const zz_pX& f)
{
long n = deg(f);
if (n <= 0)
Error("FastTraceVec: bad args");
if (n == 0) {
S.SetLength(0);
return;
}
if (n == 1) {
S.SetLength(1);
set(S[0]);
return;
}
long i;
zz_pX f1;
f1.rep.SetLength(n-1);
for (i = 0; i <= n-2; i++)
f1.rep[i] = f.rep[n-i];
f1.normalize();
zz_pX f2;
f2.rep.SetLength(n-1);
for (i = 0; i <= n-2; i++)
mul(f2.rep[i], f.rep[n-1-i], i+1);
f2.normalize();
zz_pX f3;
InvTrunc(f3, f1, n-1);
MulTrunc(f3, f3, f2, n-1);
S.SetLength(n);
S[0] = n;
for (i = 1; i < n; i++)
negate(S[i], coeff(f3, i-1));
}
void PlainTraceVec(vec_zz_p& S, const zz_pX& ff)
{
if (deg(ff) <= 0)
Error("TraceVec: bad args");
zz_pX f;
f = ff;
MakeMonic(f);
long n = deg(f);
S.SetLength(n);
if (n == 0)
return;
long k, i;
zz_p acc, t;
const zz_p *fp = f.rep.elts();;
zz_p *sp = S.elts();
sp[0] = n;
for (k = 1; k < n; k++) {
mul(acc, fp[n-k], k);
for (i = 1; i < k; i++) {
mul(t, fp[n-i], rep(sp[k-i]));
add(acc, acc, t);
}
negate(sp[k], acc);
}
}
void TraceVec(vec_zz_p& S, const zz_pX& f)
{
if (deg(f) <= NTL_zz_pX_TRACE_CROSSOVER)
PlainTraceVec(S, f);
else
FastTraceVec(S, f);
}
void ComputeTraceVec(const zz_pXModulus& F)
{
vec_zz_p& S = *((vec_zz_p *) &F.tracevec);
if (S.length() > 0)
return;
if (!F.UseFFT) {
PlainTraceVec(S, F.f);
return;
}
long i;
long n = F.n;
fftRep R;
zz_pX P, g;
g.rep.SetLength(n-1);
for (i = 1; i < n; i++)
mul(g.rep[n-i-1], F.f.rep[n-i], i);
g.normalize();
TofftRep(R, g, F.l);
mul(R, R, F.HRep);
FromfftRep(P, R, n-2, 2*n-4);
S.SetLength(n);
S[0] = n;
for (i = 1; i < n; i++)
negate(S[i], coeff(P, n-1-i));
}
void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F)
{
long n = F.n;
if (deg(a) >= n)
Error("trace: bad args");
if (F.tracevec.length() == 0)
TraceVec(F);
InnerProduct(x, a.rep, F.tracevec);
}
void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f)
{
if (deg(a) >= deg(f) || deg(f) <= 0)
Error("trace: bad args");
project(x, TraceVec(f), a);
}
void PlainResultant(zz_p& rres, const zz_pX& a, const zz_pX& b)
{
zz_p res;
if (IsZero(a) || IsZero(b))
clear(res);
else if (deg(a) == 0 && deg(b) == 0)
set(res);
else {
long d0, d1, d2;
zz_p lc;
set(res);
long n = max(deg(a),deg(b)) + 1;
zz_pX u(INIT_SIZE, n), v(INIT_SIZE, n);
u = a;
v = b;
for (;;) {
d0 = deg(u);
d1 = deg(v);
lc = LeadCoeff(v);
PlainRem(u, u, v);
swap(u, v);
d2 = deg(v);
if (d2 >= 0) {
power(lc, lc, d0-d2);
mul(res, res, lc);
if (d0 & d1 & 1) negate(res, res);
}
else {
if (d1 == 0) {
power(lc, lc, d0);
mul(res, res, lc);
}
else
clear(res);
break;
}
}
rres = res;
}
}
void ResIterHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red,
vec_zz_p& cvec, vec_long& dvec)
{
M_out(0,0).SetMaxLength(d_red);
M_out(0,1).SetMaxLength(d_red);
M_out(1,0).SetMaxLength(d_red);
M_out(1,1).SetMaxLength(d_red);
set(M_out(0,0)); clear(M_out(0,1));
clear(M_out(1,0)); set(M_out(1,1));
long goal = deg(U) - d_red;
if (deg(V) <= goal)
return;
zz_pX Q, t(INIT_SIZE, d_red);
while (deg(V) > goal) {
append(cvec, LeadCoeff(V));
append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V));
PlainDivRem(Q, U, U, V);
swap(U, V);
mul(t, Q, M_out(1,0));
sub(t, M_out(0,0), t);
M_out(0,0) = M_out(1,0);
M_out(1,0) = t;
mul(t, Q, M_out(1,1));
sub(t, M_out(0,1), t);
M_out(0,1) = M_out(1,1);
M_out(1,1) = t;
}
}
void ResHalfGCD(zz_pXMatrix& M_out, const zz_pX& U, const zz_pX& V, long d_red,
vec_zz_p& cvec, vec_long& dvec)
{
if (IsZero(V) || deg(V) <= deg(U) - d_red) {
set(M_out(0,0)); clear(M_out(0,1));
clear(M_out(1,0)); set(M_out(1,1));
return;
}
long n = deg(U) - 2*d_red + 2;
if (n < 0) n = 0;
zz_pX U1, V1;
RightShift(U1, U, n);
RightShift(V1, V, n);
if (d_red <= NTL_zz_pX_HalfGCD_CROSSOVER) {
ResIterHalfGCD(M_out, U1, V1, d_red, cvec, dvec);
return;
}
long d1 = (d_red + 1)/2;
if (d1 < 1) d1 = 1;
if (d1 >= d_red) d1 = d_red - 1;
zz_pXMatrix M1;
ResHalfGCD(M1, U1, V1, d1, cvec, dvec);
mul(U1, V1, M1);
long d2 = deg(V1) - deg(U) + n + d_red;
if (IsZero(V1) || d2 <= 0) {
M_out = M1;
return;
}
zz_pX Q;
zz_pXMatrix M2;
append(cvec, LeadCoeff(V1));
append(dvec, dvec[dvec.length()-1]-deg(U1)+deg(V1));
DivRem(Q, U1, U1, V1);
swap(U1, V1);
ResHalfGCD(M2, U1, V1, d2, cvec, dvec);
zz_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1);
mul(t, Q, M1(1,0));
sub(t, M1(0,0), t);
swap(M1(0,0), M1(1,0));
swap(M1(1,0), t);
t.kill();
t.SetMaxLength(deg(M1(1,1))+deg(Q)+1);
mul(t, Q, M1(1,1));
sub(t, M1(0,1), t);
swap(M1(0,1), M1(1,1));
swap(M1(1,1), t);
t.kill();
mul(M_out, M2, M1);
}
void ResHalfGCD(zz_pX& U, zz_pX& V, vec_zz_p& cvec, vec_long& dvec)
{
long d_red = (deg(U)+1)/2;
if (IsZero(V) || deg(V) <= deg(U) - d_red) {
return;
}
long du = deg(U);
long d1 = (d_red + 1)/2;
if (d1 < 1) d1 = 1;
if (d1 >= d_red) d1 = d_red - 1;
zz_pXMatrix M1;
ResHalfGCD(M1, U, V, d1, cvec, dvec);
mul(U, V, M1);
long d2 = deg(V) - du + d_red;
if (IsZero(V) || d2 <= 0) {
return;
}
M1(0,0).kill();
M1(0,1).kill();
M1(1,0).kill();
M1(1,1).kill();
zz_pX Q;
append(cvec, LeadCoeff(V));
append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V));
DivRem(Q, U, U, V);
swap(U, V);
ResHalfGCD(M1, U, V, d2, cvec, dvec);
mul(U, V, M1);
}
void resultant(zz_p& rres, const zz_pX& u, const zz_pX& v)
{
if (deg(u) <= NTL_zz_pX_GCD_CROSSOVER || deg(v) <= NTL_zz_pX_GCD_CROSSOVER) {
PlainResultant(rres, u, v);
return;
}
zz_pX u1, v1;
u1 = u;
v1 = v;
zz_p res, t;
set(res);
if (deg(u1) == deg(v1)) {
rem(u1, u1, v1);
swap(u1, v1);
if (IsZero(v1)) {
clear(rres);
return;
}
power(t, LeadCoeff(u1), deg(u1) - deg(v1));
mul(res, res, t);
if (deg(u1) & 1)
negate(res, res);
}
else if (deg(u1) < deg(v1)) {
swap(u1, v1);
if (deg(u1) & deg(v1) & 1)
negate(res, res);
}
// deg(u1) > deg(v1) && v1 != 0
vec_zz_p cvec;
vec_long dvec;
cvec.SetMaxLength(deg(v1)+2);
dvec.SetMaxLength(deg(v1)+2);
append(cvec, LeadCoeff(u1));
append(dvec, deg(u1));
while (deg(u1) > NTL_zz_pX_GCD_CROSSOVER && !IsZero(v1)) {
ResHalfGCD(u1, v1, cvec, dvec);
if (!IsZero(v1)) {
append(cvec, LeadCoeff(v1));
append(dvec, deg(v1));
rem(u1, u1, v1);
swap(u1, v1);
}
}
if (IsZero(v1) && deg(u1) > 0) {
clear(rres);
return;
}
long i, l;
l = dvec.length();
if (deg(u1) == 0) {
// we went all the way...
for (i = 0; i <= l-3; i++) {
power(t, cvec[i+1], dvec[i]-dvec[i+2]);
mul(res, res, t);
if (dvec[i] & dvec[i+1] & 1)
negate(res, res);
}
power(t, cvec[l-1], dvec[l-2]);
mul(res, res, t);
}
else {
for (i = 0; i <= l-3; i++) {
power(t, cvec[i+1], dvec[i]-dvec[i+2]);
mul(res, res, t);
if (dvec[i] & dvec[i+1] & 1)
negate(res, res);
}
power(t, cvec[l-1], dvec[l-2]-deg(v1));
mul(res, res, t);
if (dvec[l-2] & dvec[l-1] & 1)
negate(res, res);
PlainResultant(t, u1, v1);
mul(res, res, t);
}
rres = res;
}
void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f)
{
if (deg(f) <= 0 || deg(a) >= deg(f))
Error("norm: bad args");
if (IsZero(a)) {
clear(x);
return;
}
zz_p t;
resultant(t, f, a);
if (!IsOne(LeadCoeff(f))) {
zz_p t1;
power(t1, LeadCoeff(f), deg(a));
inv(t1, t1);
mul(t, t, t1);
}
x = t;
}
NTL_END_IMPL
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -