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

    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) 2011, 2012 Sebastian Pancratz

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

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

    Module documentation

    We represent a polynomial in $\mathbf{Q}_p[x]$ as a 
    product $p^v f(x)$, where $p$ is a prime number, 
    $v \in \mathbf{Z}$ and $f(x) \in \mathbf{Z}[x]$.

    As a data structure, we call this polynomial \emph{normalised} 
    if the polynomial $f(x)$ is \emph{normalised}, that is, if the top 
    coefficient is non-zero.

    We say this polynomial is in \emph{canonical form} if one of the 
    coefficients of $f(x)$ is a $p$-adic unit.  If $f(x)$ is the zero 
    polynomial, we require that $v = 0$.

    We say this polynomial is \emph{reduced} modulo $p^N$ if it is 
    canonical form and if all coefficients lie in the range $[0, p^N)$.

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

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

    Memory management

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

void padic_poly_init(padic_poly_t poly)

    Initialises \code{poly} for use, setting its length to zero.  
    The precision of the polynomial is set to \code{PADIC_DEFAULT_PREC}. 
    A corresponding call to \code{padic_poly_clear()} must be made 
    after finishing with the \code{padic_poly_t} to free the memory 
    used by the polynomial.

void padic_poly_init2(padic_poly_t poly, slong alloc, slong prec)

    Initialises \code{poly} with space for at least \code{alloc} coefficients 
    and sets the length to zero.  The allocated coefficients are all set to 
    zero.  The precision is set to \code{prec}.

void padic_poly_realloc(padic_poly_t poly, slong alloc, const fmpz_t p)

    Reallocates the given polynomial to have space for \code{alloc} 
    coefficients.  If \code{alloc} is zero the polynomial is cleared 
    and then reinitialised.  If the current length is greater than 
    \code{alloc} the polynomial is first truncated to length \code{alloc}.

void padic_poly_fit_length(padic_poly_t poly, slong len)

    If \code{len} is greater than the number of coefficients currently 
    allocated, then the polynomial is reallocated to have space for at 
    least \code{len} coefficients.  No data is lost when calling this 
    function.

    The function efficiently deals with the case where \code{fit_length} is 
    called many times in small increments by at least doubling the number 
    of allocated coefficients when length is larger than the number of 
    coefficients currently allocated.

void _padic_poly_set_length(padic_poly_t poly, slong len)

    Demotes the coefficients of \code{poly} beyond \code{len} and sets 
    the length of \code{poly} to \code{len}.

    Note that if the current length is greater than \code{len} the 
    polynomial may no slonger be in canonical form.

void padic_poly_clear(padic_poly_t poly)

    Clears the given polynomial, releasing any memory used.  It must 
    be reinitialised in order to be used again.

void _padic_poly_normalise(padic_poly_t poly)

    Sets the length of \code{poly} so that the top coefficient is non-zero. 
    If all coefficients are zero, the length is set to zero.  This function 
    is mainly used internally, as all functions guarantee normalisation.

void _padic_poly_canonicalise(fmpz *poly, slong *v, slong len, const fmpz_t p)

void padic_poly_canonicalise(padic_poly_t poly, const fmpz_t p)

    Brings the polynomial \code{poly} into canonical form, 
    assuming that it is normalised already.  Does \emph{not} 
    carry out any reduction.

void padic_poly_reduce(padic_poly_t poly, const padic_ctx_t ctx)

    Reduces the polynomial \code{poly} modulo $p^N$, assuming 
    that it is in canonical form already.

void padic_poly_truncate(padic_poly_t poly, slong n, const fmpz_t p)

    Truncates the polynomial to length at most~$n$.

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

    Polynomial parameters

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

slong padic_poly_degree(padic_poly_t poly)

    Returns the degree of the polynomial \code{poly}.

slong padic_poly_length(padic_poly_t poly)

    Returns the length of the polynomial \code{poly}.

slong padic_poly_val(padic_poly_t poly)

    Returns the valuation of the polynomial \code{poly}, 
    which is defined to be the minimum valuation of all 
    its coefficients.

    The valuation of the zero polynomial is~$0$.

    Note that this is implemented as a macro and can be 
    used as either a \code{lvalue} or a \code{rvalue}.

slong padic_poly_prec(padic_poly_t poly)

    Returns the precision of the polynomial \code{poly}. 

    Note that this is implemented as a macro and can be 
    used as either a \code{lvalue} or a \code{rvalue}.

    Note that increasing the precision might require 
    a call to \code{padic_poly_reduce()}.

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

    Randomisation

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

void padic_poly_randtest(padic_poly_t f, flint_rand_t state, 
                         slong len, const padic_ctx_t ctx)

    Sets $f$ to a random polynomial of length at most \code{len} 
    with entries reduced modulo $p^N$.

void padic_poly_randtest_not_zero(padic_poly_t f, flint_rand_t state,
                                  slong len, const padic_ctx_t ctx)

    Sets $f$ to a non-zero random polynomial of length at most \code{len} 
    with entries reduced modulo $p^N$.

void padic_poly_randtest_val(padic_poly_t f, flint_rand_t state, 
                             slong val, slong len, const padic_ctx_t ctx)

    Sets $f$ to a random polynomial of length at most \code{len} 
    with at most the prescribed valuation \code{val} and entries 
    reduced modulo $p^N$.

    Specifically, we aim to set the valuation to be exactly equal 
    to \code{val}, but do not check for additional cancellation 
    when creating the coefficients.

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

    Assignment and basic manipulation

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

void padic_poly_set_padic(padic_poly_t poly, const padic_t x, 
                          const padic_ctx_t ctx)

    Sets the polynomial \code{poly} to the $p$-adic number $x$, 
    reduced to the precision of the polynomial.

void padic_poly_set(padic_poly_t poly1, const padic_poly_t poly2, 
                    const padic_ctx_t ctx)

    Sets the polynomial \code{poly1} to the polynomial \code{poly2}, 
    reduced to the precision of \code{poly1}.

void padic_poly_set_si(padic_poly_t poly, slong x, const padic_ctx_t ctx)

    Sets the polynomial \code{poly} to the \code{signed slong} 
    integer $x$ reduced to the precision of the polynomial.

void padic_poly_set_ui(padic_poly_t poly, ulong x, const padic_ctx_t ctx)

    Sets the polynomial \code{poly} to the \code{unsigned slong} 
    integer $x$ reduced to the precision of the polynomial.

void padic_poly_set_fmpz(padic_poly_t poly, const fmpz_t x, 
                         const padic_ctx_t ctx)

    Sets the polynomial \code{poly} to the integer $x$ 
    reduced to the precision of the polynomial.

void padic_poly_set_fmpq(padic_poly_t poly, const fmpq_t x, 
                         const padic_ctx_t ctx)

    Sets the polynomial \code{poly} to the value of the rational $x$, 
    reduced to the precision of the polynomial.

void padic_poly_set_fmpz_poly(padic_poly_t rop, const fmpz_poly_t op, 
                              const padic_ctx_t ctx)

    Sets the polynomial \code{rop} to the integer polynomial \code{op}
    reduced to the precision of the polynomial.

void padic_poly_set_fmpq_poly(padic_poly_t rop, 
                              const fmpq_poly_t op, const padic_ctx_t ctx)

    Sets the polynomial \code{rop} to the value of the rational 
    polynomial \code{op}, reduced to the precision of the polynomial.

int padic_poly_get_fmpz_poly(fmpz_poly_t rop, const padic_poly_t op, 
                             const padic_ctx_t ctx)

    Sets the integer polynomial \code{rop} to the value of the $p$-adic 
    polynomial \code{op} and returns $1$ if the polynomial is $p$-adically 
    integral.  Otherwise, returns $0$.

void padic_poly_get_fmpq_poly(fmpq_poly_t rop, 
                              const padic_poly_t op, const padic_ctx_t ctx)

    Sets \code{rop} to the rational polynomial corresponding to 
    the $p$-adic polynomial \code{op}.

void padic_poly_zero(padic_poly_t poly)

    Sets \code{poly} to the zero polynomial.

void padic_poly_one(padic_poly_t poly)

    Sets \code{poly} to the constant polynomial $1$, 
    reduced to the precision of the polynomial.

void padic_poly_swap(padic_poly_t poly1, padic_poly_t poly2)

    Swaps the two polynomials \code{poly1} and \code{poly2}, 
    including their precisions.

    This is done efficiently by swapping pointers.

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

    Getting and setting coefficients

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

void padic_poly_get_coeff_padic(padic_t c, const padic_poly_t poly, slong n, 
                                           const padic_ctx_t ctx)

    Sets $c$ to the coefficient of $x^n$ in the polynomial, 
    reduced modulo the precision of $c$.

void padic_poly_set_coeff_padic(padic_poly_t f, slong n, const padic_t c, 
                                                const padic_ctx_t ctx)

    Sets the coefficient of $x^n$ in the polynomial $f$ to $c$, 
    reduced to the precision of the polynomial $f$.

    Note that this operation can take linear time in the length 
    of the polynomial.

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

    Comparison

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

int padic_poly_equal(const padic_poly_t poly1, const padic_poly_t poly2)

    Returns whether the two polynomials \code{poly1} and \code{poly2} 
    are equal.

int padic_poly_is_zero(const padic_poly_t poly)

    Returns whether the polynomial \code{poly} is the zero polynomial.

int padic_poly_is_one(const padic_poly_t poly, const padic_ctx_t ctx)

    Returns whether the polynomial \code{poly} is equal 
    to the constant polynomial~$1$, taking the precision 
    of the polynomial into account.

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

    Addition and subtraction

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

void _padic_poly_add(fmpz *rop, slong *rval, slong N, 
                     const fmpz *op1, slong val1, slong len1, slong N1, 
                     const fmpz *op2, slong val2, slong len2, slong N2, 
                     const padic_ctx_t ctx)

    Sets \code{(rop, *val, FLINT_MAX(len1, len2)} to the sum of 
    \code{(op1, val1, len1)} and \code{(op2, val2, len2)}.

    Assumes that the input is reduced and guarantees that this is 
    also the case for the output.

    Assumes that $\min\{v_1, v_2\} < N$.

    Supports aliasing between the output and input arguments.

void padic_poly_add(padic_poly_t f, 
                    const padic_poly_t g, const padic_poly_t h, 
                    const padic_ctx_t ctx);

    Sets $f$ to the sum $g + h$.

void _padic_poly_sub(fmpz *rop, slong *rval, 
                     const fmpz *op1, slong val1, slong len1, 
                     const fmpz *op2, slong val2, slong len2, 
                     const padic_ctx_t ctx);

    Sets \code{(rop, *val, FLINT_MAX(len1, len2)} to the difference of 
    \code{(op1, val1, len1)} and \code{(op2, val2, len2)}.

    Assumes that the input is reduced and guarantees that this is 
    also the case for the output.

    Assumes that $\min\{v_1, v_2\} < N$.

    Support aliasing between the output and input arguments.

void padic_poly_sub(padic_poly_t f, 
                    const padic_poly_t g, const padic_poly_t h, 
                    const padic_ctx_t ctx);

    Sets $f$ to the difference $g - h$.

void padic_poly_neg(padic_poly_t f, const padic_poly_t g, 
                    const padic_ctx_t ctx);

    Sets $f$ to $-g$.

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

    Scalar multiplication

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

void _padic_poly_scalar_mul_padic(fmpz *rop, slong *rval, 
                                  const fmpz *op, slong val, slong len, 
                                  const padic_t c, const padic_ctx_t ctx)

    Sets \code{(rop, *rval, len)} to \code{(op, val, len)} multiplied 
    by the scalar $c$.

    The result will only be correctly reduced if the polynomial 
    is non-zero.  Otherwise, the array \code{(rop, len)} will be 
    set to zero but the valuation \code{*rval} might be wrong.

void padic_poly_scalar_mul_padic(padic_poly_t rop, const padic_poly_t op, 
                                 const padic_t c, const padic_ctx_t ctx)

    Sets the polynomial \code{rop} to the product of the 
    polynomial \code{op} and the $p$-adic number $c$, 
    reducing the result modulo $p^N$.

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

    Multiplication

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

void _padic_poly_mul(fmpz *rop, slong *rval, slong N, 
                     const fmpz *op1, slong val1, slong len1, 
                     const fmpz *op2, slong val2, slong len2, 
                     const padic_ctx_t ctx)

    Sets \code{(rop, *rval, len1 + len2 - 1)} to the product of 
    \code{(op1, val1, len1)} and \code{(op2, val2, len2)}.

    Assumes that the resulting valuation \code{*rval}, which is 
    the sum of the valuations \code{val1} and \code{val2}, is less 
    than the precision~$N$ of the context.

    Assumes that \code{len1 >= len2 > 0}.

void padic_poly_mul(padic_poly_t res, 
                    const padic_poly_t poly1, const padic_poly_t poly2, 
                    const padic_ctx_t ctx)

    Sets the polynomial \code{res} to the product of the two polynomials 
    \code{poly1} and \code{poly2}, reduced modulo $p^N$.

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

    Powering

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

void _padic_poly_pow(fmpz *rop, slong *rval, slong N, 
                     const fmpz *op, slong val, slong len, ulong e,
                     const padic_ctx_t ctx)

    Sets the polynomial \code{(rop, *rval, e (len - 1) + 1)} to the 
    polynomial \code{(op, val, len)} raised to the power~$e$.

    Assumes that $e > 1$ and \code{len > 0}.

    Does not support aliasing between the input and output arguments.

void padic_poly_pow(padic_poly_t rop, const padic_poly_t op, ulong e, 
                    const padic_ctx_t ctx)

    Sets the polynomial \code{rop} to the polynomial \code{op} raised 
    to the power~$e$, reduced to the precision in \code{rop}.

    In the special case $e = 0$, sets \code{rop} to the constant 
    polynomial one reduced to the precision of \code{rop}.  
    Also note that when $e = 1$, this operation sets \code{rop} to 
    \code{op} and then reduces \code{rop}.

    When the valuation of the input polynomial is negative, 
    this results in a loss of $p$-adic precision.  Suppose 
    that the input polynomial is given to precision~$N$ and 
    has valuation~$v < 0$.  The result then has valuation 
    $e v < 0$ but is only correct to precision $N + (e - 1) v$.

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

    Series inversion

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

void padic_poly_inv_series(padic_poly_t g, const padic_poly_t f, slong n, 
                           const padic_ctx_t ctx)

    Computes the power series inverse $g$ of $f$ modulo $X^n$, 
    where $n \geq 1$.

    Given the polynomial $f \in \mathbf{Q}[X] \subset \mathbf{Q}_p[X]$, 
    there exists a unique polynomial $f^{-1} \in \mathbf{Q}[X]$ such that 
    $f f^{-1} = 1$ modulo $X^n$.  This function sets $g$ to $f^{-1}$ 
    reduced modulo $p^N$.

    Assumes that the constant coefficient of $f$ is non-zero.

    Moreover, assumes that the valuation of the constant coefficient 
    of $f$ is minimal among the coefficients of $f$.

    Note that the result $g$ is zero if and only if  $- \ord_p(f) \geq N$.

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

    Derivative

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

void _padic_poly_derivative(fmpz *rop, slong *rval, slong N, 
                            const fmpz *op, slong val, slong len, 
                            const padic_ctx_t ctx)

    Sets \code{(rop, rval)} to the derivative of \code{(op, val)} reduced 
    modulo $p^N$.

    Supports aliasing of the input and the output parameters.

void padic_poly_derivative(padic_poly_t rop, 
                           const padic_poly_t op, const padic_ctx_t ctx)

    Sets \code{rop} to the derivative of \code{op}, reducing the 
    result modulo the precision of \code{rop}.

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

    Shifting

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

void padic_poly_shift_left(padic_poly_t rop, const padic_poly_t op, slong n, 
                           const padic_ctx_t ctx)

    Notationally, sets the polynomial \code{rop} to the polynomial \code{op} 
    multiplied by $x^n$, where $n \geq 0$, and reduces the result.

void padic_poly_shift_right(padic_poly_t rop, const padic_poly_t op, slong n)

    Notationally, sets the polynomial \code{rop} to the polynomial 
    \code{op} after floor division by $x^n$, where $n \geq 0$, ensuring 
    the result is reduced.

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

    Evaluation

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

void _padic_poly_evaluate_padic(fmpz_t u, slong *v, slong N, 
                                const fmpz *poly, slong val, slong len, 
                                const fmpz_t a, slong b, const padic_ctx_t ctx)

void padic_poly_evaluate_padic(padic_t y, const padic_poly_t poly, 
                               const padic_t a, const padic_ctx_t ctx)

    Sets the $p$-adic number \code{y} to \code{poly} evaluated at $a$, 
    reduced in the given context.

    Suppose that the polynomial can be written as $F(X) = p^w f(X)$ 
    with $\ord_p(f) = 1$, that $\ord_p(a) = b$ and that both are 
    defined to precision~$N$.  Then $f$ is defined to precision 
    $N-w$ and so $f(a)$ is defined to precision $N-w$ when $a$ is 
    integral and $N-w+(n-1)b$ when $b < 0$, where $n = \deg(f)$.  Thus, 
    $y = F(a)$ is defined to precision $N$ when $a$ is integral and 
    $N+(n-1)b$ when $b < 0$.

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

    Composition

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

void _padic_poly_compose(fmpz *rop, slong *rval, slong N,  
                         const fmpz *op1, slong val1, slong len1, 
                         const fmpz *op2, slong val2, slong len2, 
                         const padic_ctx_t ctx)

    Sets \code{(rop, *rval, (len1-1)*(len2-1)+1)} to the composition 
    of the two input polynomials, reducing the result modulo $p^N$.

    Assumes that \code{len1} is non-zero.

    Does not support aliasing.

void padic_poly_compose(padic_poly_t rop, 
                        const padic_poly_t op1, const padic_poly_t op2, 
                        const padic_ctx_t ctx)

    Sets \code{rop} to the composition of \code{op1} and \code{op2}, 
    reducing the result in the given context.

    To be clear about the order of composition, let $f(X)$ and $g(X)$ 
    denote the polynomials \code{op1} and \code{op2}, respectively. 
    Then \code{rop} is set to $f(g(X))$.

void _padic_poly_compose_pow(fmpz *rop, slong *rval, slong N, 
                             const fmpz *op, slong val, slong len, slong k, 
                             const padic_ctx_t ctx)

    Sets \code{(rop, *rval, (len - 1)*k + 1)} to the composition of 
    \code{(op, val, len)} and the monomial $x^k$, where $k \geq 1$.

    Assumes that \code{len} is positive.

    Supports aliasing between the input and output polynomials.

void padic_poly_compose_pow(padic_poly_t rop, const padic_poly_t op, slong k, 
                            const padic_ctx_t ctx)

    Sets \code{rop} to the composition of \code{op} and the monomial $x^k$, 
    where $k \geq 1$.

    Note that no reduction takes place.

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

    Input and output

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

int padic_poly_debug(const padic_poly_t poly)

    Prints the data defining the $p$-adic polynomial \code{poly} 
    in a simple format useful for debugging purposes.

    In the current implementation, always returns $1$.

int _padic_poly_fprint(FILE *file, const fmpz *poly, slong val, slong len, 
                       const padic_ctx_t ctx)

int padic_poly_fprint(FILE *file, const padic_poly_t poly, 
                      const padic_ctx_t ctx)

    Prints a simple representation of the polynomial \code{poly} 
    to the stream \code{file}.

    A non-zero polynomial is represented by the number of coeffients, 
    two spaces, followed by a list of the coefficients, which are printed 
    in a way depending on the print mode,
    \begin{itemize}
    \item In the \code{PADIC_TERSE} mode, the coefficients are printed as 
          rational numbers.
    \item The \code{PADIC_SERIES} mode is currently not supported and will 
          raise an abort signal.
    \item In the \code{PADIC_VAL_UNIT} mode, the coefficients are printed 
          in the form $p^v u$.
    \end{itemize}

    The zero polynomial is represented by \code{"0"}.

    In the current implementation, always returns $1$.

int _padic_poly_print(const fmpz *poly, slong val, slong len, 
                      const padic_ctx_t ctx)

int padic_poly_print(const padic_poly_t poly, const padic_ctx_t ctx)

    Prints a simple representation of the polynomial \code{poly} 
    to \code{stdout}.

    In the current implementation, always returns $1$.

int _padic_poly_fprint_pretty(FILE *file, 
                              const fmpz *poly, slong val, slong len, 
                              const char *var, 
                              const padic_ctx_t ctx)

int padic_poly_fprint_pretty(FILE *file, 
                             const padic_poly_t poly, const char *var, 
                             const padic_ctx_t ctx)

int _padic_poly_print_pretty(FILE *file, 
                             const fmpz *poly, slong val, slong len, 
                             const char *var, 
                             const padic_ctx_t ctx)

int padic_poly_print_pretty(const padic_poly_t poly, const char *var, 
                            const padic_ctx_t ctx)

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

    Testing

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

int _padic_poly_is_canonical(const fmpz *op, slong val, slong len, 
                             const padic_ctx_t ctx);

int padic_poly_is_canonical(const padic_poly_t op, const padic_ctx_t ctx);

int _padic_poly_is_reduced(const fmpz *op, slong val, slong len, slong N, 
                           const padic_ctx_t ctx);

int padic_poly_is_reduced(const padic_poly_t op, const padic_ctx_t ctx);

