#ifdef T
#include "templates.h"
#include "perm.h"
static void
TEMPLATE(T, to_mat_col) (TEMPLATE(T, mat_t) mat, slong col,
TEMPLATE(T, poly_t) poly,
const TEMPLATE(T, ctx_t) ctx)
{
slong i;
for (i = 0; i < poly->length; i++)
TEMPLATE(T, set) (TEMPLATE(T, mat_entry) (mat, i, col),
poly->coeffs + i, ctx);
for (; i < mat->r; i++)
TEMPLATE(T, zero) (TEMPLATE(T, mat_entry) (mat, i, col), ctx);
}
static void
TEMPLATE(T, mat_col_to_shifted) (TEMPLATE(T, poly_t) poly,
TEMPLATE(T, mat_t) mat,
slong col, slong * shift,
const TEMPLATE(T, ctx_t) ctx)
{
slong i, j, rows = mat->r;
TEMPLATE(T, poly_fit_length) (poly, rows, ctx);
for (i = 0, j = 0; j < rows; j++)
{
if (shift[j])
TEMPLATE(T, zero) (poly->coeffs + j, ctx);
else
{
TEMPLATE(T, set) (poly->coeffs + j,
TEMPLATE(T, mat_entry) (mat, i, col), ctx);
i++;
}
}
_TEMPLATE(T, poly_set_length) (poly, rows, ctx);
_TEMPLATE(T, poly_normalise) (poly, ctx);
}
static void
__TEMPLATE(T, poly_factor_berlekamp) (TEMPLATE(T, poly_factor_t) factors,
flint_rand_t state,
const TEMPLATE(T, poly_t) f,
const TEMPLATE(T, ctx_t) ctx)
{
const slong n = TEMPLATE(T, poly_degree) (f, ctx);
TEMPLATE(T, poly_factor_t) fac1, fac2;
TEMPLATE(T, poly_t) x, x_q;
TEMPLATE(T, poly_t) x_qi, x_qi2;
TEMPLATE(T, poly_t) Q, r;
TEMPLATE(T, mat_t) matrix;
TEMPLATE(T, t) mul, coeff, neg_one;
fmpz_t q, s, pow;
slong i, nullity, col, row;
slong *shift;
TEMPLATE(T, poly_t) * basis;
if (f->length <= 2)
{
TEMPLATE(T, poly_factor_insert) (factors, f, 1, ctx);
return;
}
TEMPLATE(T, init) (coeff, ctx);
TEMPLATE(T, init) (neg_one, ctx);
TEMPLATE(T, init) (mul, ctx);
fmpz_init(q);
TEMPLATE(T, ctx_order) (q, ctx);
TEMPLATE(T, one) (neg_one, ctx);
TEMPLATE(T, neg) (neg_one, neg_one, ctx);
fmpz_init_set(s, q);
fmpz_sub_ui(s, s, 1);
fmpz_init(pow);
#if defined(FQ_NMOD_POLY_FACTOR_H) || defined(FQ_ZECH_POLY_FACTOR_H)
if (TEMPLATE(T, ctx_prime)(ctx) > UWORD(3))
{
#else
if (fmpz_cmp_ui(TEMPLATE(T, ctx_prime)(ctx), 3) > 0)
{
#endif
fmpz_set(pow, s);
fmpz_divexact_ui(pow, pow, 2);
}
TEMPLATE(T, poly_init) (x, ctx);
TEMPLATE(T, poly_init) (x_q, ctx);
TEMPLATE(T, poly_gen) (x, ctx);
TEMPLATE(T, poly_powmod_fmpz_binexp) (x_q, x, q, f, ctx);
TEMPLATE(T, poly_clear) (x, ctx);
TEMPLATE(T, mat_init) (matrix, n, n, ctx);
TEMPLATE(T, poly_init) (x_qi, ctx);
TEMPLATE(T, poly_init) (x_qi2, ctx);
TEMPLATE(T, poly_one) (x_qi, ctx);
for (i = 0; i < n; i++)
{
TEMPLATE(T, poly_set) (x_qi2, x_qi, ctx);
TEMPLATE(T, poly_get_coeff) (coeff, x_qi2, i, ctx);
TEMPLATE(T, sub_one) (coeff, coeff, ctx);
TEMPLATE(T, poly_set_coeff) (x_qi2, i, coeff, ctx);
TEMPLATE(T, to_mat_col) (matrix, i, x_qi2, ctx);
TEMPLATE(T, poly_mulmod) (x_qi, x_qi, x_q, f, ctx);
}
TEMPLATE(T, poly_clear) (x_q, ctx);
TEMPLATE(T, poly_clear) (x_qi, ctx);
TEMPLATE(T, poly_clear) (x_qi2, ctx);
nullity = n - TEMPLATE(T, mat_rref) (matrix, matrix, ctx);
basis = flint_malloc(nullity * sizeof(TEMPLATE(T, poly_t)));
shift = (slong *) flint_calloc(n, sizeof(slong));
col = 1;
row = 0;
shift[0] = 1;
for (i = 1; i < nullity; i++)
{
TEMPLATE(T, poly_init) (basis[i], ctx);
while (!TEMPLATE(T, is_zero)
(TEMPLATE(T, mat_entry) (matrix, row, col), ctx))
{
row++;
col++;
}
TEMPLATE(T, mat_col_to_shifted) (basis[i], matrix, col, shift, ctx);
TEMPLATE(T, poly_set_coeff) (basis[i], col, neg_one, ctx);
shift[col] = 1;
col++;
}
flint_free(shift);
TEMPLATE(T, mat_clear) (matrix, ctx);
if (nullity == 1)
{
TEMPLATE(T, poly_factor_insert) (factors, f, 1, ctx);
}
else
{
TEMPLATE(T, poly_t) factor, b, power, g;
TEMPLATE(T, poly_init) (factor, ctx);
TEMPLATE(T, poly_init) (b, ctx);
TEMPLATE(T, poly_init) (power, ctx);
TEMPLATE(T, poly_init) (g, ctx);
while (1)
{
do
{
TEMPLATE(T, poly_zero) (factor, ctx);
for (i = 1; i < nullity; i++)
{
TEMPLATE(T, randtest) (mul, state, ctx);
TEMPLATE(T, TEMPLATE(poly_scalar_mul, T)) (b, basis[i],
mul, ctx);
TEMPLATE(T, poly_add) (factor, factor, b, ctx);
}
TEMPLATE(T, randtest) (coeff, state, ctx);
TEMPLATE(T, poly_set_coeff) (factor, 0, coeff, ctx);
if (!TEMPLATE(T, poly_is_zero) (factor, ctx))
TEMPLATE(T, poly_make_monic) (factor, factor, ctx);
}
while (TEMPLATE(T, poly_is_zero) (factor, ctx) ||
(factor->length < 2
&& TEMPLATE(T, is_one) (factor->coeffs, ctx)));
TEMPLATE(T, poly_gcd) (g, f, factor, ctx);
if (TEMPLATE(T, poly_length) (g, ctx) != 1)
break;
#if defined(FQ_NMOD_POLY_FACTOR_H) || defined(FQ_ZECH_POLY_FACTOR_H)
if (TEMPLATE(T, ctx_prime)(ctx) > UWORD(3))
#else
if (fmpz_cmp_ui(TEMPLATE(T, ctx_prime)(ctx), 3) > 0)
#endif
TEMPLATE(T, poly_powmod_fmpz_binexp) (power, factor, pow, f,
ctx);
else
TEMPLATE(T, poly_set) (power, factor, ctx);
TEMPLATE(T, sub_one) (power->coeffs, power->coeffs, ctx);
_TEMPLATE(T, poly_normalise) (power, ctx);
TEMPLATE(T, poly_gcd) (g, power, f, ctx);
if (TEMPLATE(T, poly_length) (g, ctx) != 1)
break;
}
TEMPLATE(T, poly_clear) (power, ctx);
TEMPLATE(T, poly_clear) (factor, ctx);
TEMPLATE(T, poly_clear) (b, ctx);
if (!TEMPLATE(T, poly_is_zero) (g, ctx))
TEMPLATE(T, poly_make_monic) (g, g, ctx);
TEMPLATE(T, poly_factor_init) (fac1, ctx);
TEMPLATE(T, poly_factor_init) (fac2, ctx);
__TEMPLATE(T, poly_factor_berlekamp) (fac1, state, g, ctx);
TEMPLATE(T, poly_init) (Q, ctx);
TEMPLATE(T, poly_init) (r, ctx);
TEMPLATE(T, poly_divrem) (Q, r, f, g, ctx);
TEMPLATE(T, poly_clear) (r, ctx);
if (!TEMPLATE(T, poly_is_zero) (Q, ctx))
TEMPLATE(T, poly_make_monic) (Q, Q, ctx);
__TEMPLATE(T, poly_factor_berlekamp) (fac2, state, Q, ctx);
TEMPLATE(T, poly_factor_concat) (factors, fac1, ctx);
TEMPLATE(T, poly_factor_concat) (factors, fac2, ctx);
TEMPLATE(T, poly_factor_clear) (fac1, ctx);
TEMPLATE(T, poly_factor_clear) (fac2, ctx);
TEMPLATE(T, poly_clear) (Q, ctx);
TEMPLATE(T, poly_clear) (g, ctx);
}
for (i = 1; i < nullity; i++)
TEMPLATE(T, poly_clear) (basis[i], ctx);
flint_free(basis);
TEMPLATE(T, clear) (coeff, ctx);
TEMPLATE(T, clear) (neg_one, ctx);
TEMPLATE(T, clear) (mul, ctx);
fmpz_clear(pow);
fmpz_clear(q);
fmpz_clear(s);
}
void
TEMPLATE(T, poly_factor_berlekamp) (TEMPLATE(T, poly_factor_t) factors,
const TEMPLATE(T, poly_t) f,
const TEMPLATE(T, ctx_t) ctx)
{
slong i;
flint_rand_t r;
TEMPLATE(T, poly_t) v;
TEMPLATE(T, poly_factor_t) sq_free;
TEMPLATE(T, poly_init) (v, ctx);
TEMPLATE(T, poly_make_monic) (v, f, ctx);
TEMPLATE(T, poly_factor_init) (sq_free, ctx);
TEMPLATE(T, poly_factor_squarefree) (sq_free, v, ctx);
flint_rand_init(r);
for (i = 0; i < sq_free->num; i++)
{
__TEMPLATE(T, poly_factor_berlekamp) (factors, r, sq_free->poly + i,
ctx);
}
flint_rand_clear(r);
for (i = 0; i < factors->num; i++)
factors->exp[i] = TEMPLATE(T, poly_remove) (v, factors->poly + i, ctx);
TEMPLATE(T, poly_clear) (v, ctx);
TEMPLATE(T, poly_factor_clear) (sq_free, ctx);
}
#endif