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

    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, 2013 Sebastian Pancratz

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

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

    Data structures

    We represent an element of the extension 
    $\mathbf{Q}_q \cong \mathbf{Q}_p[X] / (f(X))$ as 
    a polynomial in $\mathbf{Q}_p[X]$ of degree less 
    than $\deg(f)$.

    As such, \code{qadic_struct} and \code{qadic_t} are 
    typedef'ed as \code{padic_poly_struct} and \code{padic_poly_t}.

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

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

    Context

    We represent an unramified extension of $\mathbf{Q}_p$ 
    via $\mathbf{Q}_q \cong \mathbf{Q}_p[X] / (f(X))$, 
    where $f \in \mathbf{Q}_p[X]$ is a monic, irreducible 
    polynomial which we assume to actually be in $\mathbf{Z}[X]$.

    The first field in the context structure is a $p$-adic 
    context struct \code{pctx}, which contains data about 
    the prime~$p$, precomputed powers, the printing mode etc.

    The polynomial $f$ is represented as a sparse polynomial 
    using two arrays $j$ and $a$ of length \code{len}, where 
    $f(X) = \sum_{i} a_{i} X^{j_{i}}$.  We also assume that 
    the array~$j$ is sorted in ascending order.

    We choose this data structure to improve reduction 
    modulo $f(X)$ in $\mathbf{Q}_p[X]$, assuming a sparse 
    polynomial $f(X)$ is chosen.

    The field \code{var} contains the name of a generator 
    of the extension, which is used when printing the 
    elements.

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

void qadic_ctx_init_conway(qadic_ctx_t ctx, 
                           const fmpz_t p, slong d, slong min, slong max, 
                           const char *var, enum padic_print_mode mode)

    Initialises the context \code{ctx} with prime $p$, extension degree $d$, 
    variable name \code{var} and printing mode \code{mode}.

    Stores powers of $p$ with exponents between \code{min} (inclusive) and 
    \code{max} exclusive.  Assumes that \code{min} is at most \code{max}. 

    Assumes that $p$ is a prime.

    Assumes that the string \code{var} is a null-terminated string 
    of length at least one.

    Assumes that the printing mode is one of \code{PADIC_TERSE}, 
    \code{PADIC_SERIES}, or \code{PADIC_VAL_UNIT}.

    This function also carries out some relevant precomputation for 
    arithmetic in $\mathbf{Q}_p / (p^N)$ such as powers of $p$ close 
    to $p^N$.

void qadic_ctx_clear(qadic_ctx_t ctx);

    Clears all memory that has been allocated as part of the context.

slong qadic_ctx_degree(const qadic_ctx_t ctx)

    Returns the extension degree.

static __inline__ void qadic_ctx_print(const qadic_ctx_t ctx)

    Prints the data from the given context.

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

    Memory management

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

void qadic_init(qadic_t rop)

    Initialises the element \code{rop}, setting its value to~$0$.

void qadic_init2(qadic_t rop, slong prec)

    Initialises the element \code{rop} with the given output precision, 
    setting the value to~$0$.

void qadic_clear(qadic_t rop)

    Clears the element \code{rop}.

void _fmpz_poly_reduce(fmpz *R, slong lenR, 
                       const fmpz *a, const slong *j, slong len)

    Reduces a polynomial \code{(R, lenR)} modulo a sparse monic 
    polynomial $f(X) = \sum_{i} a_{i} X^{j_{i}}$ of degree at 
    least~$2$.

    Assumes that the array $j$ of positive length \code{len} is 
    sorted in ascending order.

    Allows zero-padding in \code{(R, lenR)}.

void _fmpz_mod_poly_reduce(fmpz *R, slong lenR, 
    const fmpz *a, const slong *j, slong len, const fmpz_t p)

    Reduces a polynomial \code{(R, lenR)} modulo a sparse monic 
    polynomial $f(X) = \sum_{i} a_{i} X^{j_{i}}$ of degree at 
    least~$2$ in $\mathbf{Z}/(p)$, where $p$ is typically a prime 
    power.

    Assumes that the array $j$ of positive length \code{len} is 
    sorted in ascending order.

    Allows zero-padding in \code{(R, lenR)}.

void qadic_reduce(qadic_t rop, const qadic_ctx_t ctx)

    Reduces \code{rop} modulo $f(X)$ and $p^N$.

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

    Properties

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

slong qadic_val(const qadic_t op)

    Returns the valuation of \code{op}.

slong qadic_prec(const qadic_t op)

    Returns the precision of \code{op}.

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

    Randomisation

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

void qadic_randtest(qadic_t rop, flint_rand_t state, const qadic_ctx_t ctx)

    Generates a random element of $\mathbf{Q}_q$.

void qadic_randtest_not_zero(qadic_t rop, flint_rand_t state, 
                             const qadic_ctx_t ctx)

    Generates a random non-zero element of $\mathbf{Q}_q$.

void qadic_randtest_val(qadic_t rop, flint_rand_t state, slong v, 
                        const qadic_ctx_t ctx)

    Generates a random element of $\mathbf{Q}_q$ with prescribed 
    valuation \code{val}.

    Note that if $v \geq N$ then the element is necessarily zero.

void qadic_randtest_int(qadic_t rop, flint_rand_t state, const qadic_ctx_t ctx)

    Generates a random element of $\mathbf{Q}_q$ with non-negative valuation.

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

    Assignments and conversions

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

void qadic_set(qadic_t rop, const qadic_t op)

    Sets \code{rop} to \code{op}.

void qadic_zero(qadic_t rop)

    Sets \code{rop} to zero.

void qadic_one(qadic_t rop, const qadic_ctx_t ctx)

    Sets \code{rop} to one, reduced in the given context.

    Note that if the precision $N$ is non-positive then \code{rop} 
    is actually set to zero.

void qadic_gen(qadic_t rop, const qadic_ctx_t ctx)

    Sets \code{rop} to the generator $X$ for the extension 
    when $N > 0$, and zero otherwise.  If the extension degree 
    is one, raises an abort signal.

void qadic_set_ui(qadic_t rop, ulong op, const qadic_ctx_t ctx)

    Sets \code{rop} to the integer \code{op}, reduced in the 
    context.

int qadic_get_padic(padic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    If the element \code{op} lies in $\mathbf{Q}_p$, sets \code{rop} 
    to its value and returns~$1$;  otherwise, returns~$0$.

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

    Comparison

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

int qadic_is_zero(const qadic_t op)

    Returns whether \code{op} is equal to zero.

int qadic_is_one(const qadic_t op, const qadic_ctx_t ctx)

    Returns whether \code{op} is equal to one in the given 
    context.

int qadic_equal(const qadic_t op1, const qadic_t op2)

    Returns whether \code{op1} and \code{op2} are equal.

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

    Basic arithmetic

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

void qadic_add(qadic_t rop, const qadic_t op1, const qadic_t op2, 
               const qadic_ctx_t ctx)

    Sets \code{rop} to the sum of \code{op1} and \code{op2}.

    Assumes that both \code{op1} and \code{op2} are reduced in the 
    given context and ensures that \code{rop} is, too.

void qadic_sub(qadic_t rop, const qadic_t op1, const qadic_t op2, 
               const qadic_ctx_t ctx)

    Sets \code{rop} to the difference of \code{op1} and \code{op2}.

    Assumes that both \code{op1} and \code{op2} are reduced in the 
    given context and ensures that \code{rop} is, too.

void qadic_neg(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Sets \code{rop} to the negative of \code{op}.

    Assumes that \code{op} is reduced in the given context and 
    ensures that \code{rop} is, too.

void qadic_mul(qadic_t rop, const qadic_t op1, const qadic_t op2, 
               const qadic_ctx_t ctx)

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

void _qadic_inv(fmpz *rop, const fmpz *op, slong len, 
                const fmpz *a, const slong *j, slong lena, 
                const fmpz_t p, slong N)

    Sets \code{(rop, d)} to the inverse of \code{(op, len)} 
    modulo $f(X)$ given by \code{(a,j,lena)} and $p^N$.

    Assumes that \code{(op,len)} has valuation~$0$, that is, 
    that it represents a $p$-adic unit.

    Assumes that \code{len} is at most $d$.

    Does not support aliasing.

void qadic_inv(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Sets \code{rop} to the inverse of \code{op}, reduced in the given context.

void _qadic_pow(fmpz *rop, const fmpz *op, slong len, const fmpz_t e, 
                const fmpz *a, const slong *j, slong lena, 
                const fmpz_t p)

    Sets \code{(rop, 2*d-1)} to \code{(op,len)} raised to the power~$e$, 
    reduced modulo $f(X)$ given by \code{(a, j, lena)} and $p$, which 
    is expected to be a prime power.

    Assumes that $e \geq 0$ and that \code{len} is positive and at most~$d$.

    Although we require that \code{rop} provides space for 
    $2d - 1$ coefficients, the output will be reduces modulo 
    $f(X)$, which is a polynomial of degree~$d$.

    Does not support aliasing.

void qadic_pow(qadic_t rop, const qadic_t op, const fmpz_t e, 
               const qadic_ctx_t ctx)

    Sets \code{rop} the \code{op} raised to the power~$e$.

    Currently assumes that $e \geq 0$.

    Note that for any input \code{op}, \code{rop} is set to one in the 
    given context whenever $e = 0$.

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

    Special functions

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

void _qadic_exp_rectangular(fmpz *rop, const fmpz *op, slong v, slong len, 
                            const fmpz *a, const slong *j, slong lena, 
                            const fmpz_t p, slong N, const fmpz_t pN)

    Sets \code{(rop, 2*d - 1)} to the exponential of \code{(op, v, len)} 
    reduced modulo $p^N$, assuming that the series converges.

    Assumes that \code{(op, v, len)} is non-zero.

    Does not support aliasing.

int qadic_exp_rectangular(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Returns whether the exponential series converges at \code{op} 
    and sets \code{rop} to its value reduced modulo in the given 
    context.

void _qadic_exp_balanced(fmpz *rop, const fmpz *x, slong v, slong len, 
                         const fmpz *a, const slong *j, slong lena, 
                         const fmpz_t p, slong N, const fmpz_t pN)

    Sets \code{(rop, d)} to the exponential of \code{(op, v, len)} 
    reduced modulo $p^N$, assuming that the series converges.

    Assumes that \code{len} is in $[1,d)$ but supports zero padding, 
    including the special case when \code{(op, len)} is zero.

    Supports aliasing between \code{rop} and \code{op}.

int qadic_exp_balanced(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Returns whether the exponential series converges at \code{op} 
    and sets \code{rop} to its value reduced modulo in the given 
    context.

void _qadic_exp(fmpz *rop, const fmpz *op, slong v, slong len, 
                const fmpz *a, const slong *j, slong lena, 
                const fmpz_t p, slong N)

    Sets \code{(rop, 2*d - 1)} to the exponential of \code{(op, v, len)} 
    reduced modulo $p^N$, assuming that the series converges.

    Assumes that \code{(op, v, len)} is non-zero.

    Does not support aliasing.

int qadic_exp(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Returns whether the exponential series converges at \code{op} 
    and sets \code{rop} to its value reduced modulo in the given 
    context.

    The exponential series converges if the valuation of \code{op} 
    is at least~$2$ or $1$ when $p$ is even or odd, respectively.

void _qadic_log_rectangular(fmpz *z, const fmpz *y, slong v, slong len, 
                            const fmpz *a, const slong *j, slong lena, 
                            const fmpz_t p, slong N, const fmpz_t pN)

    Computes 
    \begin{equation*}
    z = - \sum_{i = 1}^{\infty} \frac{y^i}{i} \pmod{p^N}.
    \end{equation*}

    Note that this can be used to compute the $p$-adic logarithm 
    via the equation 
    \begin{align*}
    \log(x) & = \sum_{i=1}^{\infty} (-1)^{i-1} \frac{(x-1)^i}{i} \\
            & = - \sum_{i=1}^{\infty} \frac{(1-x)^i}{i}.
    \end{align*}

    Assumes that $y = 1 - x$ is non-zero and that $v = \ord_p(y)$ 
    is at least $1$ when $p$ is odd and at least $2$ when $p = 2$ 
    so that the series converges.

    Assumes that $y$ is reduced modulo $p^N$.

    Assumes that $v < N$, and in particular $N \geq 2$.

    Supports aliasing between $y$ and $z$.

int qadic_log_rectangular(qadic_t rop, const qadic_t op, const padic_ctx_t ctx)

    Returns whether the $p$-adic logarithm function converges at 
    \code{op}, and if so sets \code{rop} to its value.

void _qadic_log_balanced(fmpz *z, const fmpz *y, slong len, 
                         const fmpz *a, const slong *j, slong lena, 
                         const fmpz_t p, slong N, const fmpz_t pN)

    Computes $(z, d)$ as 
    \begin{equation*}
    z = - \sum_{i = 1}^{\infty} \frac{y^i}{i} \pmod{p^N}.
    \end{equation*}

    Assumes that $v = \ord_p(y)$ is at least $1$ when $p$ is odd and 
    at least $2$ when $p = 2$ so that the series converges.

    Supports aliasing between $z$ and $y$.

int qadic_log_balanced(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Returns whether the $p$-adic logarithm function converges at 
    \code{op}, and if so sets \code{rop} to its value.

void _qadic_log(fmpz *z, const fmpz *y, slong v, slong len, 
                const fmpz *a, const slong *j, slong lena, 
                const fmpz_t p, slong N, const fmpz_t pN)

    Computes $(z, d)$ as 
    \begin{equation*}
    z = - \sum_{i = 1}^{\infty} \frac{y^i}{i} \pmod{p^N}.
    \end{equation*}

    Note that this can be used to compute the $p$-adic logarithm 
    via the equation 
    \begin{align*}
    \log(x) & = \sum_{i=1}^{\infty} (-1)^{i-1} \frac{(x-1)^i}{i} \\
            & = - \sum_{i=1}^{\infty} \frac{(1-x)^i}{i}.
    \end{align*}

    Assumes that $y = 1 - x$ is non-zero and that $v = \ord_p(y)$ 
    is at least $1$ when $p$ is odd and at least $2$ when $p = 2$ 
    so that the series converges.

    Assumes that $(y, d)$ is reduced modulo $p^N$.

    Assumes that $v < N$, and hence in particular $N \geq 2$.

    Supports aliasing between $z$ and $y$.

int qadic_log(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Returns whether the $p$-adic logarithm function converges at 
    \code{op}, and if so sets \code{rop} to its value.

    The $p$-adic logarithm function is defined by the usual series 
    \begin{equation*}
    \log_p(x) = \sum_{i=1}^{\infty} (-1)^{i-1} \frac{(x-1)^i}{i}
    \end{equation*}
    but this only converges when $\ord_p(x)$ is at least $2$ or $1$ 
    when $p = 2$ or $p > 2$, respectively.

void _qadic_frobenius_a(fmpz *rop, slong e, 
                    const fmpz *a, const slong *j, slong lena, 
                    const fmpz_t p, slong N)

    Computes $\sigma^e(X) \bmod{p^N}$ where $X$ is such that 
    $\mathbf{Q}_q \cong \mathbf{Q}_p[X]/(f(X))$.

    Assumes that the precision $N$ is at least~$2$ and that the 
    extension is non-trivial, i.e.\ $d \geq 2$.

    Assumes that $0 < e < d$.

    Sets \code{(rop, 2*d-1)}, although the actual length of the 
    output will be at most~$d$.

void _qadic_frobenius(fmpz *rop, const fmpz *op, slong len, slong e, 
                  const fmpz *a, const slong *j, slong lena, 
                  const fmpz_t p, slong N)

    Sets \code{(rop, 2*d-1)} to $\Sigma$ evaluated at \code{(op, len)}.

    Assumes that \code{len} is positive but at most~$d$.

    Assumes that $0 < e < d$.

    Does not support aliasing.

void qadic_frobenius(qadic_t rop, const qadic_t op, slong e, const qadic_ctx_t ctx)

    Evaluates the homomorphism $\Sigma^e$ at \code{op}.

    Recall that $\mathbf{Q}_q / \mathbf{Q}_p$ is Galois with Galois group 
    $\langle \Sigma \rangle \cong \langle \sigma \rangle$, which is also 
    isomorphic to $\mathbf{Z}/d\mathbf{Z}$, where 
    $\sigma \in \Gal(\mathbf{F}_q/\mathbf{F}_p)$ is the Frobenius element 
    $\sigma \colon x \mapsto x^p$ and $\Sigma$ is its lift to 
    $\Gal(\mathbf{Q}_q/\mathbf{Q}_p)$.

    This functionality is implemented as \code{GaloisImage()} in Magma.

void _qadic_teichmuller(fmpz *rop, const fmpz *op, slong len, 
                        const fmpz *a, const slong *j, slong lena, 
                        const fmpz_t p, slong N)

    Sets \code{(rop, d)} to the Teichm\"uller lift of \code{(op, len)} 
    modulo~$p^N$.

    Does not support aliasing.

void qadic_teichmuller(qadic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Sets \code{rop} to the Teichm\"uller lift of \code{op} to the 
    precision given in the context.

    For a unit \code{op}, this is the unique $(q-1)$th root of unity 
    which is congruent to \code{op} modulo~$p$.

    Sets \code{rop} to zero if \code{op} is zero in the given context.

    Raises an exception if the valuation of \code{op} is negative.

void _qadic_trace(fmpz_t rop, const fmpz *op, slong len, 
                  const fmpz *a, const slong *j, slong lena, const fmpz_t pN)

void qadic_trace(padic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Sets \code{rop} to the trace of \code{op}.

    For an element $a \in \mathbf{Q}_q$, multiplication by $a$ defines 
    a $\mathbf{Q}_p$-linear map on $\mathbf{Q}_q$.  We define the trace 
    of $a$ as the trace of this map.  Equivalently, if $\Sigma$ generates 
    $\Gal(\mathbf{Q}_q / \mathbf{Q}_p)$ then the trace of $a$ is equal to 
    $\sum_{i=0}^{d-1} \Sigma^i (a)$.

void _qadic_norm(fmpz_t rop, const fmpz *op, slong len, 
                 const fmpz *a, const slong *j, slong lena, 
                 const fmpz_t p, slong N)

    Sets \code{rop} to the norm of the element \code{(op,len)} 
    in $\mathbf{Z}_q$ to precision $N$, where \code{len} is at 
    least one.

    The result will be reduced modulo $p^N$.

    Note that whenever \code{(op,len)} is a unit, so is its norm. 
    Thus, the output \code{rop} of this function will typically 
    not have to be canonicalised or reduced by the caller.

void qadic_norm(padic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Computes the norm of \code{op} to the given precision.

    Algorithm selection is automatic depending on the input.

void qadic_norm_analytic(padic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Whenever \code{op} has valuation greater than $(p-1)^{-1}$, this 
    routine computes its norm \code{rop} via 
    \begin{equation*}
    \Norm (x) = \exp \Bigl( \bigl( \Trace \log (x) \bigr) \Bigr).
    \end{equation*}

    In the special case that \code{op} lies in $\mathbf{Q}_p$, returns 
    its norm as $\Norm(x) = x^d$, where $d$ is the extension degree.

    Otherwise, raises an \code{abort} signal.

    The complexity of this implementation is quasi-linear in $d$ and $N$, 
    and polynomial in $\log p$.

void qadic_norm_resultant(padic_t rop, const qadic_t op, const qadic_ctx_t ctx)

    Sets \code{rop} to the norm of \code{op}, using the formula 
    \begin{equation*}
    \Norm(x) = \ell(f)^{-\deg(a)} \Res(f(X), a(X)),
    \end{equation*}
    where $\mathbf{Q}_q \cong \mathbf{Q}_p[X] / (f(X))$, $\ell(f)$ is the 
    leading coefficient of $f(X)$, and $a(X) \in mathbf{Q}_p[X]$ denotes 
    the same polynomial as $x$.

    The complexity of the current implementation is given by 
    $\mathcal{O}(d^4 M(N \log p))$, where $M(n)$ denotes the 
    complexity of multiplying to $n$-bit integers.

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

    Output

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

int qadic_fprint_pretty(FILE *file, const qadic_t op, const qadic_ctx_t ctx)

    Prints a pretty representation of \code{op} to \code{file}.

    In the current implementation, always returns~$1$.  The return code is 
    part of the function's signature to allow for a later implementation to 
    return the number of characters printed or a non-positive error code.

int qadic_print_pretty(const qadic_t op, const qadic_ctx_t ctx)

    Prints a pretty representation of \code{op} to \code{stdout}.

    In the current implementation, always returns~$1$.  The return code is 
    part of the function's signature to allow for a later implementation to 
    return the number of characters printed or a non-positive error code.

