#include <pari/pari.h>
/* A in Z[X], return kernel of (Frob - Id) over Fp[X] / A */
GEN
Berlekamp_Ker(GEN A, GEN p)
{
long j, N = degpol(A);
GEN v, w, Q = zeromat(N, N);
w = v = FpXQ_pow(polx[varn(A)], p, A, p); /* x^p mod (A,p) */
for (j = 2; j <= N; j++)
{
gel(Q, j) = RX_to_RV(w, N);
gcoeff(Q, j, j) = addis(gcoeff(Q, j, j), -1);
if (j < N)
{
pari_sp av = avma; /*FpXQ_mul is not stack clean*/
w = gerepileupto(av, FpXQ_mul(w, v, A, p)); /* w *= v (mod A,p)*/
}
}
return FpM_ker(Q, p);
}
long
nbfact(GEN A, GEN p)
{
pari_sp av = avma;
GEN K = Berlekamp_Ker(A, p);
long dim = glength(K);
avma = av; return dim;
}
int
main()
{
GEN p, A;
pari_init(1000000, 2);
printf("p = "); p = lisGEN(stdin);
printf("A = "); A = lisGEN(stdin);
if (!p || !A) err(talker, "read failed");
if (!BSW_psp(p)) err(talker, "%Z is not prime", p);
if (typ(A) != t_POL || !FpX_is_squarefree(A, p))
err(talker, "%Z is not a squarefree polynomial", A);
pariputsf("... has %ld factor(s) mod %Z.\n", nbfact(A, p), p);
}