#include <gmp.h>
#include "longlong.h"
#include "fmpz.h"
#include "fmpz_mat.h"
void _fmpz_mat_resize_van_hoeij(fmpz_mat_t M, slong r, slong c)
{
slong i, j;
fmpz * old_entries = M->entries;
M->entries = (fmpz *) flint_realloc(M->entries, r*c*sizeof(fmpz));
mpn_zero((nn_ptr) M->entries + M->r*M->c, r*c - M->r*M->c);
if (r != M->r)
{
M->rows = (fmpz **) flint_realloc(M->rows, r*sizeof(fmpz *));
for (i = r - 1; i >= 1; i--)
{
fmpz * old_row = M->entries + (i - 1)*M->c;
fmpz * new_row = M->entries + i*c;
for (j = M->c - 1; j >= 0; j--)
fmpz_swap(old_row + j, new_row + j);
}
for (i = M->r - 1; i >= 0; i--)
{
slong diff = (slong) (M->rows[i] - old_entries);
if (M->rows[i] >= old_entries + M->c*M->r)
flint_throw(FLINT_ERROR, "(%s)\n", __func__);
j = diff/M->c;
M->rows[i + 1] = M->entries + (j + 1)*c;
}
M->rows[0] = M->entries;
} else
{
for (i = r - 1; i >= 0; i--)
{
fmpz * old_row = M->entries + i*M->c;
fmpz * new_row = M->entries + i*c;
for (j = M->c - 1; j >= 0; j--)
fmpz_swap(old_row + j, new_row + j);
}
for (i = 0; i < r; i++)
{
slong diff = (slong) (M->rows[i] - old_entries);
j = diff/M->c;
M->rows[i] = M->entries + j*c;
}
}
M->r = r;
M->c = c;
}
int fmpz_mat_next_col_van_hoeij(fmpz_mat_t M, fmpz_t P,
fmpz_mat_t col, slong exp, slong U_exp)
{
slong j, k, r = col->r;
slong bit_r = FLINT_MAX(r, 20);
slong s = M->r;
fmpz_mat_t U, x, y;
fmpz_t P_trunc;
k = fmpz_bits(P) - bit_r - bit_r/2;
if (k < exp + (slong) FLINT_BIT_COUNT(r + 1))
return 0;
fmpz_init(P_trunc);
fmpz_mat_init(x, r, 1);
fmpz_mat_init(y, s, 1);
fmpz_mat_window_init(U, M, 0, 0, s, r);
k -= U_exp;
if (k >= 0)
{
fmpz_mat_scalar_tdiv_q_2exp(x, col, k);
fmpz_tdiv_q_2exp(P_trunc, P, k);
} else
{
fmpz_mat_scalar_mul_2exp(x, col, -k);
fmpz_mul_2exp(P_trunc, P, -k);
}
fmpz_mat_mul(y, U, x);
fmpz_mat_scalar_tdiv_q_2exp(y, y, U_exp);
fmpz_mat_scalar_smod(y, y, P_trunc);
_fmpz_mat_resize_van_hoeij(M, s + 1, M->c + 1);
fmpz_set(M->rows[0] + M->c - 1, P_trunc);
for (j = 1; j < M->r; j++)
fmpz_set(M->rows[j] + M->c - 1, y->rows[j - 1]);
fmpz_mat_clear(x);
fmpz_mat_clear(y);
fmpz_clear(P_trunc);
fmpz_mat_window_clear(U);
return 1;
}