#include "bee2/core/util.h"
#include "bee2/math/pp.h"
#include "bee2/math/ww.h"
size_t ppDeg(const word a[], size_t n)
{
return wwBitSize(a, n) - SIZE_1;
}
bool_t ppIsIrred(const word a[], size_t n, void* stack)
{
size_t i;
word* h = (word*)stack;
word* d = h + n;
stack = d + n;
n = wwWordSize(a, n);
if (wwCmpW(a, n, 1) <= 0)
return FALSE;
wwSetW(h, n, 4);
for (i = ppDeg(a, n) / 2; i; --i)
{
wwFlipBit(h, 1);
if (wwIsZero(h, n))
return FALSE;
ppGCD(d, h, n, a, n, stack);
if (wwCmpW(d, n, 1) != 0)
return FALSE;
wwFlipBit(h, 1);
if (i > 1)
ppSqrMod(h, h, a, n, stack);
}
return TRUE;
}
size_t ppIsIrred_deep(size_t n)
{
return O_OF_W(2 * n);
}
void ppMinPoly(word b[], const word a[], size_t l, void* stack)
{
const size_t n = W_OF_B(l);
const size_t m = W_OF_B(l + 1);
size_t na, nb;
word* aa = (word*)stack;
word* bb = aa + 2 * n;
word* q = bb + 2 * n + 1;
word* r = q + n + 2;
word* da = r + 2 * n;
word* db = da + m;
stack = db + m + n + 2;
ASSERT(wwIsValid(b, m) && wwIsValid(a, 2 * n));
wwCopy(aa, a, 2 * n);
wwTrimHi(aa, 2 * n, 2 * l);
na = wwWordSize(aa, 2 * n);
nb = W_OF_B(2 * l + 1);
wwSetZero(bb, nb);
wwSetBit(bb, 2 * l, 1);
wwSetW(da, m, 1);
wwSetZero(db, m);
while (ppDeg(aa, na) + 1 > l)
{
size_t nq, nda;
ppDiv(q, r, bb, nb, aa, na, stack);
nq = wwWordSize(q, nb - na + 1);
nda = wwWordSize(da, m);
while (nq--)
db[nq + nda] ^= ppAddMulW(db + nq, da, nda, q[nq], stack);
ASSERT(nq + nda <= m || wwIsZero(db, nq + nda - m));
wwSwap(da, db, m);
wwCopy(bb, aa, na);
nb = na;
wwCopy(aa, r, na);
na = wwWordSize(aa, na);
}
wwCopy(b, da, m);
}
size_t ppMinPoly_deep(size_t l)
{
const size_t n = W_OF_B(l);
const size_t m = W_OF_B(l + 1);
return O_OF_W(8 * n + 2 * m + 5) + ppAddMulW_deep(m);
}
void ppMinPolyMod(word b[], const word a[], const word mod[], size_t n,
void* stack)
{
size_t l, i;
word* t = (word*)stack;
word* s = t + n;
stack = s + 2 * n;
ASSERT(wwIsValid(b, n) && wwIsValid(a, n) && wwIsValid(mod, n));
ASSERT(wwCmpW(mod, n, 1) > 0 && wwCmp(a, mod, n) < 0);
l = ppDeg(mod, n);
wwCopy(t, a, n);
wwSetBit(s, 2 * l - 1, wwTestBit(t, 0));
for (i = 2 * l - 1; i--;)
{
ppMulMod(t, t, a, mod, n, stack);
wwSetBit(s, i, wwTestBit(t, 0));
}
wwTrimHi(s, 2 * n, 2 * l);
ppMinPoly(b, s, l, stack);
}
size_t ppMinPolyMod_deep(size_t n)
{
return ppMulMod_deep(n) + ppMinPoly_deep(n * B_PER_W);
}