#include <pari/pari.h>
#define swap(x,y) {GEN _z=(GEN)x; x=y; y=(long)_z;}
/* Assumes 'a' square Flm. Returns det(a) mod l. IN PLACE (destroys a) */
ulong
Flm_det(GEN a, ulong l)
{
long i, j, k, nbco = lg(a)-1;
ulong p, invp, x = 1UL;
for (i = 1; i < nbco; i++)
{
p = coeff(a,i,i); k=i;
if (!p)
{
do k++; while(k <= nbco && !gcoeff(a,i,k));
if (k > nbco) return 0;
}
if (k != i)
{
swap(a[i], a[k]);
x = l - x;
p = coeff(a,i,i); /* pivot */
}
x = Fl_mul(x, p, l);
invp = Fl_inv(p, l);
for (k = i+1; k <= nbco; k++)
{
ulong m = coeff(a,i,k);
if (m)
{
m = l - Fl_mul(m, invp, l);
for (j = i+1; j <= nbco; j++)
coeff(a,j,k) = Fl_add(coeff(a,j,k), Fl_mul(m, coeff(a,j,i), l), l);
}
}
}
return Fl_mul(x, coeff(a,nbco,nbco), l);
}
static long
center(ulong u, ulong p) { return (long) (u > (p >> 1))? u - p: u; }
/* 27449 = prime(3000) */
byteptr
init_modular(ulong *p) { *p = 27449; return diffptr + 3000; }
/* assume A is a ZM */
GEN
ZM_det(GEN A)
{
pari_sp av = avma;
ulong Dp, p; /* p will loop over prime numbers, Dp = D mod p */
byteptr ptr = init_modular(&p);
GEN D = NULL, qp, q = gun;
for(;;)
{
pari_sp av2 = avma;
NEXT_PRIME_VIADIFF_CHECK(p, ptr);
Dp = Flm_det(ZM_to_Flm(A, p), p);
avma = av2;
qp = muliu(q, p);
if (!D)
D = stoi( center(Dp, p) );
else
if (Z_incremental_CRT(&D, Dp, q, qp, p)) break;
fprintferr("p = %lu, Dp = %lu, D = %Z\n", p, Dp, D);
q = qp;
}
return gerepileuptoint(av, D);
}
int
main()
{
GEN A;
pari_init(1000000,2);
printf("A = "); A = lisGEN(stdin);
pariputsf( "det(A) is probably %Z\n", ZM_det(A) );
}