/*=============================================================================

    This file is part of FLINT.

    FLINT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    FLINT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with FLINT; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA

=============================================================================*/
/******************************************************************************

    Copyright (C) 2012,2013 Andres Goens
    Copyright (C) 2012 Sebastian Pancratz
    Copyright (C) 2013 Mike Hansen

******************************************************************************/

*******************************************************************************

    Memory Management

*******************************************************************************

void fq_zech_poly_factor_init(fq_zech_poly_factor_t fac, const fq_zech_ctx_t ctx)

    Initialises \code{fac} for use. An \code{fq_zech_poly_factor_t}
    represents a polynomial in factorised form as a product of
    polynomials with associated exponents.

void fq_zech_poly_factor_clear(fq_zech_poly_factor_t fac, const fq_zech_ctx_t ctx)

    Frees all memory associated with \code{fac}.

void fq_zech_poly_factor_realloc(fq_zech_poly_factor_t fac, slong alloc,
                            const fq_zech_ctx_t ctx)

    Reallocates the factor structure to provide space for
    precisely \code{alloc} factors.

void fq_zech_poly_factor_fit_length(fq_zech_poly_factor_t fac, slong len,
                               const fq_zech_ctx_t ctx)

    Ensures that the factor structure has space for at least
    \code{len} factors.  This functions takes care of the case of
    repeated calls by always at least doubling the number of factors
    the structure can hold.

*******************************************************************************

    Basic Operations

*******************************************************************************

void fq_zech_poly_factor_set(fq_zech_poly_factor_t res, const fq_zech_poly_factor_t fac,
                        const fq_zech_ctx_t ctx)

    Sets \code{res} to the same factorisation as \code{fac}.

void fq_zech_poly_factor_print_pretty(const fq_zech_poly_factor_t fac, const fq_zech_ctx_t ctx)

    Pretty-prints the entries of \code{fac} to standard output.

void fq_zech_poly_factor_print(const fq_zech_poly_factor_t fac, const fq_zech_ctx_t ctx)

    Prints the entries of \code{fac} to standard output.

void fq_zech_poly_factor_insert(fq_zech_poly_factor_t fac, const fq_zech_poly_t poly,
                           slong exp, const fq_zech_ctx_t ctx)

    Inserts the factor \code{poly} with multiplicity \code{exp} into
    the factorisation \code{fac}.

    If \code{fac} already contains \code{poly}, then \code{exp} simply
    gets added to the exponent of the existing entry.

void fq_zech_poly_factor_concat(fq_zech_poly_factor_t res, const fq_zech_poly_factor_t fac,
                           const fq_zech_ctx_t ctx)

    Concatenates two factorisations.

    This is equivalent to calling \code{fq_zech_poly_factor_insert()}
    repeatedly with the individual factors of \code{fac}.

    Does not support aliasing between \code{res} and \code{fac}.

void fq_zech_poly_factor_pow(fq_zech_poly_factor_t fac, slong exp, const fq_zech_ctx_t ctx)

    Raises \code{fac} to the power \code{exp}.

ulong fq_zech_poly_remove(fq_zech_poly_t f, const fq_zech_poly_t p, const fq_zech_ctx_t ctx)

    Removes the highest possible power of \code{p} from \code{f} and
    returns the exponent.

*******************************************************************************

    Irreducibility Testing

*******************************************************************************

int fq_zech_poly_is_irreducible(const fq_zech_poly_t f, const fq_zech_ctx_t ctx)

    Returns 1 if the polynomial \code{f} is irreducible, otherwise returns 0.

int fq_zech_poly_is_irreducible_ddf(const fq_zech_poly_t f, const fq_zech_ctx_t ctx)

    Returns 1 if the polynomial \code{f} is irreducible, otherwise returns 0.
    Uses fast distinct-degree factorisation.

int fq_zech_poly_is_irreducible_ben_or(const fq_zech_poly_t f, const fq_zech_ctx_t ctx)

    Returns 1 if the polynomial \code{f} is irreducible, otherwise returns 0.
    Uses Ben-Or's irreducibility test.

int _fq_zech_poly_is_squarefree(const fq_zech_struct * f, slong len, const fq_zech_ctx_t ctx)

    Returns 1 if \code{(f, len)} is squarefree, and 0 otherwise. As a
    special case, the zero polynomial is not considered squarefree.
    There are no restrictions on the length.

int fq_zech_poly_is_squarefree(const fq_zech_poly_t f, const fq_zech_ctx_t ctx)

    Returns 1 if \code{f} is squarefree, and 0 otherwise. As a special
    case, the zero polynomial is not considered squarefree.

*******************************************************************************

    Factorisation

*******************************************************************************

int fq_zech_poly_factor_equal_deg_prob(fq_zech_poly_t factor, flint_rand_t state,
                                  const fq_zech_poly_t pol, slong d,
                                  const fq_zech_ctx_t ctx)

    Probabilistic equal degree factorisation of \code{pol} into
    irreducible factors of degree \code{d}. If it passes, a factor is
    placed in factor and 1 is returned, otherwise 0 is returned and
    the value of factor is undetermined.

    Requires that \code{pol} be monic, non-constant and squarefree.

void fq_zech_poly_factor_equal_deg(fq_zech_poly_factor_t factors, const fq_zech_poly_t pol,
                              slong d, const fq_zech_ctx_t ctx)

    Assuming \code{pol} is a product of irreducible factors all of
    degree \code{d}, finds all those factors and places them in
    factors.  Requires that \code{pol} be monic, non-constant and
    squarefree.

void fq_zech_poly_factor_distinct_deg(fq_zech_poly_factor_t res, const fq_zech_poly_t poly,
                                 slong * const *degs, const fq_zech_ctx_t ctx)

    Factorises a monic non-constant squarefree polymnomial \code{poly}
    of degree n into factors $f[d]$ such that for $1 \leq d \leq n$
    $f[d]$ is the product of the monic irreducible factors of
    \code{poly} of degree $d$. Factors are stored in \code{res},
    assotiated powers of irreducible polynomials are stored in
    \code{degs} in the same order as factors.

    Requires that \code{degs} have enough space for irreducible polynomials'
    powers (maximum space required is $n * sizeof(slong)$).

void fq_zech_poly_factor_squarefree(fq_zech_poly_factor_t res, const fq_zech_poly_t f,
                               const fq_zech_ctx_t ctx)

    Sets \code{res} to a squarefree factorization of \code{f}.

void fq_zech_poly_factor(fq_zech_poly_factor_t res, fq_zech_t lead, const fq_zech_poly_t f,
                                                                     const fq_zech_ctx_t ctx)

    Factorises a non-constant polynomial \code{f} into monic
    irreducible factors choosing the best algorithm for given modulo
    and degree. The output \code{lead} is set to the leading coefficient of $f$
    upon return. Choice of algorithm is based on heuristic measurments.

void fq_zech_poly_factor_cantor_zassenhaus(fq_zech_poly_factor_t res, const fq_zech_poly_t f,
                                      const fq_zech_ctx_t ctx)

    Factorises a non-constant polynomial \code{f} into monic
    irreducible factors using the Cantor-Zassenhaus algorithm.

void fq_zech_poly_factor_kaltofen_shoup(fq_zech_poly_factor_t res, const fq_zech_poly_t poly,
                                   const fq_zech_ctx_t ctx)

    Factorises a non-constant polynomial \code{f} into monic
    irreducible factors using the fast version of Cantor-Zassenhaus
    algorithm proposed by Kaltofen and Shoup (1998). More precisely
    this algorithm uses a “baby step/giant step” strategy for the
    distinct-degree factorization step.

void fq_zech_poly_factor_berlekamp(fq_zech_poly_factor_t factors, const fq_zech_poly_t f,
                              const fq_zech_ctx_t ctx)

    Factorises a non-constant polynomial \code{f} into monic
    irreducible factors using the Berlekamp algorithm.

void fq_zech_poly_factor_with_berlekamp(fq_zech_poly_factor_t res, fq_zech_t leading_coeff,
                                   const fq_zech_poly_t f, const fq_zech_ctx_t)

    Factorises a general polynomial \code{f} into monic irreducible
    factors and sets \code{leading_coeff} to the leading coefficient
    of \code{f}, or 0 if \code{f} is the zero polynomial.

    This function first checks for small special cases, deflates
    \code{f} if it is of the form $p(x^m)$ for some $m > 1$, then
    performs a square-free factorisation, and finally runs Berlekamp
    on all the individual square-free factors.

void fq_zech_poly_factor_with_cantor_zassenhaus(fq_zech_poly_factor_t res,
                                           fq_zech_t leading_coeff
                                           const fq_zech_poly_t f,
                                           const fq_zech_ctx_t ctx)

    Factorises a general polynomial \code{f} into monic irreducible
    factors and sets \code{leading_coeff} to the leading coefficient
    of \code{f}, or 0 if \code{f} is the zero polynomial.

    This function first checks for small special cases, deflates
    \code{f} if it is of the form $p(x^m)$ for some $m > 1$, then
    performs a square-free factorisation, and finally runs
    Cantor-Zassenhaus on all the individual square-free factors.

void fq_zech_poly_factor_with_kaltofen_shoup(fq_zech_poly_factor_t res,
                                        fq_zech_t leading_coeff,
                                        const fq_zech_poly_t f,
                                        const fq_zech_ctx_t ctx)

    Factorises a general polynomial \code{f} into monic irreducible
    factors and sets \code{leading_coeff} to the leading coefficient
    of \code{f}, or 0 if \code{f} is the zero polynomial.

    This function first checks for small special cases, deflates
    \code{f} if it is of the form $p(x^m)$ for some $m > 1$, then
    performs a square-free factorisation, and finally runs
    Kaltofen-Shoup on all the individual square-free factors.

void fq_zech_poly_iterated_frobenius_preinv(fq_zech_poly_t *rop, slong n,
                                            const fq_zech_poly_t v,
                                            const fq_zech_poly_t vinv,
                                            const fq_zech_ctx_t ctx)

    Sets \code{rop[i]} to be $x^{q^i} mod v$ for $0 <= i < n$.

    It is required that \code{vinv} is the inverse of the reverse of
    \code{v} mod \code{x^lenv}.
