#include "perm.h"
#include "ulong_extras.h"
#include "nmod_mat.h"
#include "fmpz.h"
#include "fmpz_mat.h"
int
fmpz_mat_rref_upper_certify_lu_mod_p(fmpz_mat_t E, fmpz_t den, const fmpz_mat_t A,
slong rank, const slong * P, const slong * pivs)
{
slong i, j, m, n;
fmpz_mat_t B, C, D, E2, F, FD;
m = fmpz_mat_nrows(A);
n = fmpz_mat_ncols(A);
fmpz_mat_init(B, rank, rank);
fmpz_mat_init(C, rank, n - rank);
for (i = 0; i < rank; i++)
{
for (j = 0; j < rank; j++)
fmpz_set(fmpz_mat_entry(B, i, j),
fmpz_mat_entry(A, P[i], pivs[j]));
for (j = 0; j < n - rank; j++)
fmpz_set(fmpz_mat_entry(C, i, j),
fmpz_mat_entry(A, P[i], pivs[rank + j]));
}
fmpz_mat_init(E2, rank, n - rank);
if (!fmpz_mat_solve(E2, den, B, C))
{
flint_throw(FLINT_ERROR, "(fmpz_mat_rref_upper_certify_lu_mod_p): "
"Singular input matrix for solve.\n");
}
fmpz_mat_clear(B);
fmpz_mat_clear(C);
for (i = 0; i < rank; i++)
{
fmpz_set(fmpz_mat_entry(E, i, pivs[i]), den);
for (j = 0; j < n - rank; j++)
fmpz_set(fmpz_mat_entry(E, i, pivs[rank + j]),
fmpz_mat_entry(E2, i, j));
}
fmpz_mat_clear(E2);
if (!fmpz_mat_is_in_rref_with_rank(E, den, rank))
return 0;
fmpz_mat_init(D, n, n - rank);
for (j = 0; j < n - rank; j++)
{
fmpz_set(fmpz_mat_entry(D, pivs[rank + j], j), den);
for (i = 0; i < rank; i++)
fmpz_neg(fmpz_mat_entry(D, pivs[i], j),
fmpz_mat_entry(E, i, pivs[rank + j]));
}
fmpz_mat_init(F, m - rank, n);
for (i = 0; i < m - rank; i++)
for (j = 0; j < n; j++)
fmpz_set(fmpz_mat_entry(F, i, j),
fmpz_mat_entry(A, P[rank + i], j));
fmpz_mat_init(FD, m - rank, n - rank);
fmpz_mat_mul(FD, F, D);
fmpz_mat_clear(F);
fmpz_mat_clear(D);
if (!fmpz_mat_is_zero(FD))
{
fmpz_mat_clear(FD);
return 0;
}
fmpz_mat_clear(FD);
return 1;
}
int
fmpz_mat_rank_certify_lu_mod_p(const fmpz_mat_t A,
slong rank, const slong * P, const slong * pivs)
{
int result;
fmpz_mat_t E;
fmpz_t den;
fmpz_init(den);
fmpz_mat_init(E, rank, A->c);
result = fmpz_mat_rref_upper_certify_lu_mod_p(E, den, A, rank, P, pivs);
fmpz_clear(den);
fmpz_mat_clear(E);
return result;
}
slong
fmpz_mat_rref_mul(fmpz_mat_t R, fmpz_t den, const fmpz_mat_t A)
{
nmod_mat_t Amod;
fmpz_mat_t E;
ulong p;
slong i, j, m, n, rank, * pivs, * P;
m = fmpz_mat_nrows(A);
n = fmpz_mat_ncols(A);
pivs = (slong *) flint_malloc(n * sizeof(slong));
P = _perm_init(m);
p = 1 << 16;
while (1)
{
p = n_nextprime(p, 1);
nmod_mat_init(Amod, m, n, p);
fmpz_mat_get_nmod_mat(Amod, A);
rank = nmod_mat_lu_with_pivots(P, pivs, Amod);
nmod_mat_clear(Amod);
if (rank == n)
{
fmpz_mat_one(R);
fmpz_one(den);
break;
}
fmpz_mat_init(E, rank, n);
if (fmpz_mat_rref_upper_certify_lu_mod_p(E, den, A, rank, P, pivs))
{
for (i = 0; i < rank; i++)
for (j = 0; j < n; j++)
fmpz_set(fmpz_mat_entry(R, i, j), fmpz_mat_entry(E, i, j));
for (i = rank; i < m; i++)
for (j = 0; j < n; j++)
fmpz_zero(fmpz_mat_entry(R, i, j));
fmpz_mat_clear(E);
break;
}
else
{
fmpz_mat_clear(E);
}
}
flint_free(pivs);
_perm_clear(P);
return rank;
}