/*
Copyright (C) 2011 Andy Novocin
Copyright (C) 2011 William Hart
Copyright (C) 2011 Sebastian Pancratz
Copyright (C) 2020 Daniel Schultz
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#include
#include "fmpz_poly.h"
static void _fmpz_poly_product(
fmpz_poly_t res,
const fmpz_poly_struct * lifted_fac,
const slong * subset,
slong len,
const fmpz_t P,
const fmpz_t leadf,
fmpz_poly_struct ** stack,
fmpz_poly_struct * tmp)
{
slong i, j, k;
fmpz_poly_struct * t;
k = 0;
for (i = 0; i < len; i++)
{
if (subset[i] < 0)
continue;
stack[k] = (fmpz_poly_struct *) lifted_fac + subset[i];
k++;
for (j = k - 1; j > 0 && stack[j - 1]->length < stack[j]->length; j--)
{
t = stack[j - 1];
stack[j - 1] = stack[j];
stack[j] = t;
}
}
while (k > 1)
{
for (j = 1; j < k; j++)
FLINT_ASSERT(stack[j - 1]->length >= stack[j]->length);
fmpz_poly_mul(res, stack[k - 2], stack[k - 1]);
fmpz_poly_scalar_smod_fmpz(res, res, P);
k--;
stack[k - 1] = tmp + k - 1; /* make sure stack[k - 1] is writeable */
fmpz_poly_swap(res, stack[k - 1]);
for (j = k - 1; j > 0 && stack[j - 1]->length < stack[j]->length; j--)
{
t = stack[j - 1];
stack[j - 1] = stack[j];
stack[j] = t;
}
}
if (k == 1)
{
fmpz_poly_scalar_mul_fmpz(res, stack[0], leadf);
fmpz_poly_scalar_smod_fmpz(res, res, P);
}
else
{
FLINT_ASSERT(0);
fmpz_poly_one(res);
}
}
void fmpz_poly_factor_zassenhaus_recombination(
fmpz_poly_factor_t final_fac,
const fmpz_poly_factor_t lifted_fac,
const fmpz_poly_t F,
const fmpz_t P,
slong exp)
{
const slong r = lifted_fac->num;
slong * subset;
slong k, len;
fmpz_poly_t Fcopy, Q, tryme;
fmpz_poly_struct * tmp;
fmpz_poly_struct ** stack;
fmpz_poly_struct * f;
subset = (slong *) flint_malloc(r*sizeof(slong));
for (k = 0; k < r; k++)
subset[k] = k;
stack = (fmpz_poly_struct **) flint_malloc(r*sizeof(fmpz_poly_struct *));
tmp = (fmpz_poly_struct *) flint_malloc(r*sizeof(fmpz_poly_struct));
for (k = 0; k < r; k++)
fmpz_poly_init(tmp + k);
fmpz_poly_init(Q);
fmpz_poly_init(tryme);
fmpz_poly_init(Fcopy);
f = (fmpz_poly_struct *) F;
len = r;
for (k = 1; k <= len/2; k++)
{
zassenhaus_subset_first(subset, len, k);
while (1)
{
_fmpz_poly_product(tryme, lifted_fac->p, subset, len, P,
fmpz_poly_lead(f), stack, tmp);
fmpz_poly_primitive_part(tryme, tryme);
if (fmpz_poly_divides(Q, f, tryme))
{
fmpz_poly_factor_insert(final_fac, tryme, exp);
f = Fcopy; /* make sure f is writeable */
fmpz_poly_swap(f, Q);
len -= k;
if (!zassenhaus_subset_next_disjoint(subset, len + k))
break;
}
else
{
if (!zassenhaus_subset_next(subset, len))
break;
}
}
}
if (fmpz_poly_degree(f) > 0)
{
fmpz_poly_factor_insert(final_fac, f, exp);
}
else
{
FLINT_ASSERT(fmpz_poly_is_one(f));
}
fmpz_poly_clear(Fcopy);
fmpz_poly_clear(tryme);
fmpz_poly_clear(Q);
flint_free(stack);
for (k = 0; k < r; k++)
fmpz_poly_clear(tmp + k);
flint_free(tmp);
flint_free(subset);
}
void fmpz_poly_factor_zassenhaus_recombination_with_prune(
fmpz_poly_factor_t final_fac,
const fmpz_poly_factor_t lifted_fac,
const fmpz_poly_t F,
const fmpz_t P,
slong exp,
const zassenhaus_prune_t Z)
{
const slong r = lifted_fac->num;
slong * subset;
slong i, k, len, total;
fmpz_poly_t Fcopy, Q, tryme;
fmpz_poly_struct * tmp;
fmpz_poly_struct ** stack;
fmpz_poly_struct * f;
subset = (slong *) flint_malloc(r*sizeof(slong));
for (k = 0; k < r; k++)
subset[k] = k;
stack = (fmpz_poly_struct **) flint_malloc(r*sizeof(fmpz_poly_struct *));
tmp = (fmpz_poly_struct *) flint_malloc(r*sizeof(fmpz_poly_struct));
for (k = 0; k < r; k++)
fmpz_poly_init(tmp + k);
fmpz_poly_init(Q);
fmpz_poly_init(tryme);
fmpz_poly_init(Fcopy);
f = (fmpz_poly_struct *) F;
len = r;
for (k = 1; k <= len/2; k++)
{
zassenhaus_subset_first(subset, len, k);
while (1)
{
total = 0;
for (i = 0; i < len; i++)
if (subset[i] >= 0)
total += fmpz_poly_degree(lifted_fac->p + subset[i]);
if (!zassenhaus_prune_degree_is_possible(Z, total))
{
if (!zassenhaus_subset_next(subset, len))
break;
continue;
}
_fmpz_poly_product(tryme, lifted_fac->p, subset, len, P,
fmpz_poly_lead(f), stack, tmp);
fmpz_poly_primitive_part(tryme, tryme);
if (fmpz_poly_divides(Q, f, tryme))
{
fmpz_poly_factor_insert(final_fac, tryme, exp);
f = Fcopy; /* make sure f is writeable */
fmpz_poly_swap(f, Q);
len -= k;
if (!zassenhaus_subset_next_disjoint(subset, len + k))
break;
}
else
{
if (!zassenhaus_subset_next(subset, len))
break;
}
}
}
if (fmpz_poly_degree(f) > 0)
{
fmpz_poly_factor_insert(final_fac, f, exp);
}
else
{
FLINT_ASSERT(fmpz_poly_is_one(f));
}
fmpz_poly_clear(Fcopy);
fmpz_poly_clear(tryme);
fmpz_poly_clear(Q);
flint_free(stack);
for (k = 0; k < r; k++)
fmpz_poly_clear(tmp + k);
flint_free(tmp);
flint_free(subset);
}