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

    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

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

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

    Data structures

    A $p$-adic number of type \code{padic_t} comprises a unit~$u$, 
    a valuation~$v$, and a precision~$N$.

    We provide the following macros to access these fields, so that 
    code can be developed somewhat independently from the underlying 
    data layout.

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

fmpz * padic_unit(const padic_t op)

    Returns the unit part of the $p$-adic number as a FLINT integer, which 
    can be used as an operand for the \code{fmpz} functions.

slong padic_val(const padic_t op)

    Returns the valuation part of the $p$-adic number.

    Note that this function is implemented as a macro and that 
    the expression \code{padic_val(op)} can be used as both an 
    \emph{lvalue} and an \emph{rvalue}.

slong padic_get_val(const padic_t op)

    Returns the valuation part of the $p$-adic number.

slong padic_prec(const padic_t op)

    Returns the precision of the $p$-adic number.

    Note that this function is implemented as a macro and that 
    the expression \code{padic_prec(op)} can be used as both an 
    \emph{lvalue} and an \emph{rvalue}.

slong padic_get_prec(const padic_t op)

    Returns the precision of the $p$-adic number.

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

    Context

    A context object for $p$-adic arithmetic contains data pertinent to 
    $p$-adic computations, but which we choose not to store with each 
    element individually.

    Currently, this includes the prime number~$p$, its \code{double} 
    inverse in case of word-sized primes, precomputed powers of $p$ 
    in the range given by \code{min} and \code{max}, and the printing 
    mode.

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

void padic_ctx_init(padic_ctx_t ctx, const fmpz_t p, slong min, slong max, 
                    enum padic_print_mode mode)

    Initialises the context \code{ctx} with the given data.

    Assumes that $p$ is a prime.  This is not verified but the subsequent 
    behaviour is undefined if $p$ is a composite number.

    Assumes that \code{min} and \code{max} are non-negative and that 
    \code{min} is at most \code{max}, raising an \code{abort} signal 
    otherwise.

    Assumes that the printing mode is one of \code{PADIC_TERSE}, 
    \code{PADIC_SERIES}, or\\ \code{PADIC_VAL_UNIT}.  Using the example 
    $x = 7^{-1} 12$ in $\mathbf{Q}_7$, these behave as follows:
    \begin{itemize}
    \item In \code{PADIC_TERSE} mode, a $p$-adic number is printed 
          in the same way as a rational number, e.g.\ \code{12/7}.
    \item In \code{PADIC_SERIES} mode, a $p$-adic number is printed 
          digit by digit, e.g.\ \code{5*7^-1 + 1}.
    \item In \code{PADIC_VAL_UNIT} mode, a $p$-adic number is 
          printed showing the valuation and unit parts separately, 
          e.g.\ \code{12*7^-1}.
    \end{itemize}

void padic_ctx_clear(padic_ctx_t ctx);

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

int _padic_ctx_pow_ui(fmpz_t rop, ulong e, const padic_ctx_t ctx)

    Sets \code{rop} to $p^e$ as efficiently as possible, where 
    \code{rop} is expected to be an uninitialised \code{fmpz_t}.

    If the return value is non-zero, it is the responsibility of 
    the caller to clear the returned integer.

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

    Memory management

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

void padic_init(padic_t rop)

    Initialises the $p$-adic number with the precision set to 
    \code{PADIC_DEFAULT_PREC}, which is defined as~$20$.

void padic_init2(padic_t rop, slong N)

    Initialises the $p$-adic number \code{rop} with precision~$N$.

void padic_clear(padic_t rop)

    Clears all memory used by the $p$-adic number \code{rop}.

void _padic_canonicalise(padic_t rop, const padic_ctx_t ctx)

    Brings the $p$-adic number \code{rop} into canonical form.

    That is to say, ensures that either $u = v = 0$ or 
    $p \nmid u$.  There is no reduction modulo a power 
    of $p$.

void _padic_reduce(padic_t rop, const padic_ctx_t ctx)

    Given a $p$-adic number \code{rop} in canonical form, 
    reduces it modulo $p^N$.

void padic_reduce(padic_t rop, const padic_ctx_t ctx)

    Ensures that the $p$-adic number \code{rop} is reduced.

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

    Randomisation

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

void padic_randtest(padic_t rop, flint_rand_t state, const padic_ctx_t ctx)

    Sets \code{rop} to a random $p$-adic number modulo $p^N$ with valuation 
    in the range $[- \ceil{N/10}, N)$, $[N - \ceil{-N/10}, N)$, or $[-10, 0)$ 
    as $N$ is positive, negative or zero, whenever \code{rop} is non-zero.

void padic_randtest_not_zero(padic_t rop, flint_rand_t state, 
                             const padic_ctx_t ctx)

    Sets \code{rop} to a random non-zero $p$-adic number modulo $p^N$, 
    where the range of the valuation is as for the function 
    \code{padic_randtest()}.

void padic_randtest_int(padic_t rop, flint_rand_t state, 
                        const padic_ctx_t ctx)

    Sets \code{rop} to a random $p$-adic integer modulo $p^N$.

    Note that whenever $N \leq 0$, \code{rop} is set to zero.

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

    Assignments and conversions

    All assignment functions set the value of \code{rop} from \code{op}, 
    reduced to the precision of \code{rop}.

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

void padic_set(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Sets \code{rop} to the $p$-adic number \code{op}.

void padic_set_si(padic_t rop, slong op, const padic_ctx_t ctx)

    Sets the $p$-adic number \code{rop} to the 
    \code{slong} integer \code{op}.

void padic_set_ui(padic_t rop, ulong op, const padic_ctx_t ctx)

    Sets the $p$-adic number \code{rop} to the \code{ulong} 
    integer \code{op}.

void padic_set_fmpz(padic_t rop, const fmpz_t op, const padic_ctx_t ctx)

    Sets the $p$-adic number \code{rop} to the integer \code{op}.

void padic_set_fmpq(padic_t rop, const fmpq_t op, const padic_ctx_t ctx)

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

void padic_set_mpz(padic_t rop, const mpz_t op, const padic_ctx_t ctx)

    Sets the $p$-adic number \code{rop} to the MPIR integer \code{op}.

void padic_set_mpq(padic_t rop, const mpq_t op, const padic_ctx_t ctx)

    Sets \code{rop} to the MPIR rational \code{op}.

void padic_get_fmpz(fmpz_t rop, const padic_t op, const padic_ctx_t ctx)

    Sets the integer \code{rop} to the exact $p$-adic integer \code{op}.

    If \code{op} is not a $p$-adic integer, raises an \code{abort} signal.

void padic_get_fmpq(fmpq_t rop, const padic_t op, const padic_ctx_t ctx)

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

void padic_get_mpz(mpz_t rop, const padic_t op, const padic_ctx_t ctx)

    Sets the MPIR integer \code{rop} to the $p$-adic integer \code{op}.

    If \code{op} is not a $p$-adic integer, raises an \code{abort} signal.

void padic_get_mpq(mpq_t rop, const padic_t op, const padic_ctx_t ctx)

    Sets the MPIR rational \code{rop} to the value of \code{op}.

void padic_swap(padic_t op1, padic_t op2)

    Swaps the two $p$-adic numbers \code{op1} and \code{op2}.

    Note that this includes swapping the precisions.  In particular, this 
    operation is not equivalent to swapping \code{op1} and \code{op2} 
    using \code{padic_set()} and an auxiliary variable whenever the 
    precisions of the two elements are different.

void padic_zero(padic_t rop)

    Sets the $p$-adic number \code{rop} to zero.

void padic_one(padic_t rop)

    Sets the $p$-adic number \code{rop} to one, reduced modulo the 
    precision of \code{rop}.

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

    Comparison

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

int padic_is_zero(const padic_t op)

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

int padic_is_one(const padic_t op)

    Returns whether \code{op} is equal to one, that is, whether 
    $u = 1$ and $v = 0$.

int padic_equal(const padic_t op1, const padic_t op2)

    Returns whether \code{op1} and \code{op2} are equal, that is, 
    whether $u_1 = u_2$ and $v_1 = v_2$.

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

    Arithmetic operations

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

slong * _padic_lifts_exps(slong *n, slong N)

    Given a positive integer $N$ define the sequence 
    $a_0 = N, a_1 = \ceil{a_0/2}, \dotsc, a_{n-1} = \ceil{a_{n-2}/2} = 1$.
    Then $n = \ceil{\log_2 N} + 1$.

    This function sets $n$ and allocates and returns the array~$a$.

void _padic_lifts_pows(fmpz *pow, const slong *a, slong n, const fmpz_t p)

    Given an array~$a$ as computed above, this function 
    computes the corresponding powers of $p$, that is, 
    \code{pow[i]} is equal to $p^{a_i}$.

void padic_add(padic_t rop, const padic_t op1, const padic_t op2, 
               const padic_ctx_t ctx)

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

void padic_sub(padic_t rop, const padic_t op1, const padic_t op2, 
               const padic_ctx_t ctx)

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

void padic_neg(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Sets \code{rop} to the additive inverse of \code{op}.

void padic_mul(padic_t rop, const padic_t op1, const padic_t op2, 
               const padic_ctx_t ctx)

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

void padic_shift(padic_t rop, const padic_t op, slong v, const padic_ctx_t ctx)

    Sets \code{rop} to the product of \code{op} and $p^v$.

void padic_div(padic_t rop, const padic_t op1, const padic_t op2, 
               const padic_ctx_t ctx)

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

void _padic_inv_precompute(padic_inv_t S, const fmpz_t p, slong N)

    Pre-computes some data and allocates temporary space for 
    $p$-adic inversion using Hensel lifting.

void _padic_inv_clear(padic_inv_t S)

    Frees the memory used by $S$.

void _padic_inv_precomp(fmpz_t rop, const fmpz_t op, const padic_inv_t S)

    Sets \code{rop} to the inverse of \code{op} modulo $p^N$, 
    assuming that \code{op} is a unit and $N \geq 1$.

    In the current implementation, allows aliasing, but this might 
    change in future versions.

    Uses some data $S$ precomputed by calling the function 
    \code{_padic_inv_precompute()}.  Note that this object 
    is not declared \code{const} and in fact it carries a field 
    providing temporary work space.  This allows repeated calls of 
    this function to avoid repeated memory allocations, as used 
    e.g.\ by the function \code{padic_log()}.

void _padic_inv(fmpz_t rop, const fmpz_t op, const fmpz_t p, slong N)

    Sets \code{rop} to the inverse of \code{op} modulo $p^N$, 
    assuming that \code{op} is a unit and $N \geq 1$.

    In the current implementation, allows aliasing, but this might 
    change in future versions.

void padic_inv(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Computes the inverse of \code{op} modulo $p^N$.

    Suppose that \code{op} is given as $x = u p^v$. 
    Raises an \code{abort} signal if $v < -N$.  Otherwise, 
    computes the inverse of $u$ modulo $p^{N+v}$.

    This function employs Hensel lifting of an inverse modulo $p$.

int padic_sqrt(padic_rop, const padic_t op, const padic_ctx_t ctx)

    Returns whether \code{op} is a $p$-adic square.  If this is 
    the case, sets \code{rop} to one of the square roots;  otherwise, 
    the value of \code{rop} is undefined.

    We have the following theorem:

    Let $u \in \mathbf{Z}^{\times}$.  Then $u$ is a 
    square if and only if $u \bmod p$ is a square in 
    $\mathbf{Z} / p \mathbf{Z}$, for $p > 2$, or if 
    $u \bmod 8$ is a square in $\mathbf{Z} / 8 \mathbf{Z}$, 
    for $p = 2$.

void padic_pow_si(padic_t rop, const padic_t op, slong e, 
                  const padic_ctx_t ctx)

    Sets \code{rop} to \code{op} raised to the power~$e$, 
    which is defined as one whenever $e = 0$.

    Assumes that some computations involving $e$ and the 
    valuation of \code{op} do not overflow in the \code{slong} 
    range.

    Note that if the input $x = p^v u$ is defined modulo $p^N$ 
    then $x^e = p^{ev} u^e$ is defined modulo $p^{N + (e - 1) v}$, 
    which is a precision loss in case $v < 0$.

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

    Exponential

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

slong _padic_exp_bound(slong v, slong N, const fmpz_t p)

    Returns an integer $i$ such that for all $j \geq i$ we have 
    $\ord_p(x^j / j!) \geq N$, where $\ord_p(x) = v$.

    When $p$ is a word-sized prime, 
    returns $\ceil{\frac{(p-1)N - 1}{(p-1)v - 1}}$.
    Otherwise, returns $\ceil{N/v}$.

    Assumes that $v < N$.  Moreover, $v$ has to be at least $2$ or $1$, 
    depending on whether $p$ is $2$ or odd.

void _padic_exp_rectangular(fmpz_t rop, const fmpz_t u, slong v, 
                                        const fmpz_t p, slong N)

void _padic_exp_balanced(fmpz_t rop, const fmpz_t u, slong v, 
                                     const fmpz_t p, slong N)

void _padic_exp(fmpz_t rop, const fmpz_t u, slong v, const fmpz_t p, slong N)

    Sets \code{rop} to the $p$-exponential function evaluated at 
    $x = p^v u$, reduced modulo~$p^N$.

    Assumes that $x \neq 0$, that $\ord_p(x) < N$ and that 
    $\exp(x)$ converges, that is, that $\ord_p(x)$ is at least 
    $2$ or $1$ depending on whether the prime~$p$ is $2$ or odd.

    Supports aliasing between \code{rop} and $u$.

int padic_exp(padic_t y, const padic_t x, const padic_ctx_t ctx)

    Returns whether the $p$-adic exponential function converges at 
    the $p$-adic number $x$, and if so sets $y$ to its value.

    The $p$-adic exponential function is defined by the usual series 
    \begin{equation*}
    \exp_p(x) = \sum_{i = 0}^{\infty} \frac{x^i}{i!}
    \end{equation*}
    but this only converges only when $\ord_p(x) > 1 / (p - 1)$.  For 
    elements $x \in \mathbf{Q}_p$, this means that $\ord_p(x) \geq 1$ 
    when $p \geq 3$ and $\ord_2(x) \geq 2$ when $p = 2$.

int padic_exp_rectangular(padic_t y, const padic_t x, const padic_ctx_t ctx)

    Returns whether the $p$-adic exponential function converges at 
    the $p$-adic number $x$, and if so sets $y$ to its value.

    Uses a rectangular splitting algorithm to evaluate the series 
    expression of $\exp(x) \bmod{p^N}$.

int padic_exp_balanced(padic_t y, const padic_t x, const padic_ctx_t ctx)

    Returns whether the $p$-adic exponential function converges at 
    the $p$-adic number $x$, and if so sets $y$ to its value.

    Uses a balanced approach, balancing the size of chunks of $x$ 
    with the valuation and hence the rate of convergence, which 
    results in a quasi-linear algorithm in $N$, for fixed $p$.

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

    Logarithm

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

slong _padic_log_bound(slong v, slong N, const fmpz_t p)

    Returns $b$ such that for all $i \geq b$ we have 
    \begin{equation*}
    i v - \ord_p(i) \geq N
    \end{equation*}
    where $v \geq 1$.

    Assumes that $1 \leq v < N$ or $2 \leq v < N$ when $p$ is 
    odd or $p = 2$, respectively, and also that $N < 2^{f-2}$ 
    where $f$ is \code{FLINT_BITS}.

void _padic_log(fmpz_t z, const fmpz_t y, slong v, const fmpz_t p, slong N)

void _padic_log_rectangular(fmpz_t z, 
                            const fmpz_t y, slong v, const fmpz_t p, slong N)

void _padic_log_satoh(fmpz_t z, 
                      const fmpz_t y, slong v, const fmpz_t p, slong N)

void _padic_log_balanced(fmpz_t z, 
                         const fmpz_t y, slong v, const fmpz_t p, slong N)

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

    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 $v < N$, and hence in particular $N \geq 2$.

    Does not support aliasing between $y$ and $z$.

int padic_log(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Returns whether the $p$-adic logarithm function converges at 
    the $p$-adic number \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.

int padic_log_rectangular(padic_t rop, const padic_t op, const padic_ctx_t ctx)

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

    Uses a rectangular splitting algorithm to evaluate the series 
    expression of $\log(x) \bmod{p^N}$.

int padic_log_satoh(padic_t rop, const padic_t op, const padic_ctx_t ctx)

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

    Uses an algorithm based on a result of Satoh, Skjernaa and Taguchi 
    that $\ord_p\bigl(a^{p^k} - 1\bigr) > k$, which implies that 
    \begin{equation*}
    \log(a) \equiv p^{-k} \Bigl( \log\bigl(a^{p^k}\bigr) \pmod{p^{N+k}} 
                                                      \Bigr) \pmod{p^N}.
    \end{equation*}

int padic_log_balanced(padic_t rop, const padic_t op, const padic_ctx_t ctx)

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

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

    Special functions

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

void _padic_teichmuller(fmpz_t rop, const fmpz_t op, const fmpz_t p, slong N)

    Computes the Teichmuller lift of the $p$-adic unit \code{op}, 
    assuming that $N \geq 1$.

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

void padic_teichmuller(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Computes the Teichmuller lift of the $p$-adic unit \code{op}.

    If \code{op} is a $p$-adic integer divisible by $p$, sets \code{rop} 
    to zero, which satisfies $t^p - t = 0$, although it is clearly not 
    a $(p-1)$-st root of unity.

    If \code{op} has negative valuation, raises an \code{abort} signal.

ulong padic_val_fac_ui_2(ulong n)

    Computes the $2$-adic valuation of $n!$.

    Note that since $n$ fits into an \code{ulong}, so does 
    $\ord_2(n!)$ since $\ord_2(n!) \leq (n - 1) / (p - 1) = n - 1$.

ulong padic_val_fac_ui(ulong n, const fmpz_t p)

    Computes the $p$-adic valuation of $n!$.

    Note that since $n$ fits into an \code{ulong}, so does 
    $\ord_p(n!)$ since $\ord_p(n!) \leq (n - 1) / (p - 1)$.

void padic_val_fac(fmpz_t rop, const fmpz_t op, const fmpz_t p)

    Sets \code{rop} to the $p$-adic valuation of the factorial 
    of \code{op}, assuming that \code{op} is non-negative.

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

    Input and output

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

char * padic_get_str(char * str, const padic_t op, const padic_ctx_t ctx)

    Returns the string representation of the $p$-adic number \code{op}
    according to the printing mode set in the context.

    If \code{str} is \code{NULL} then a new block of memory is allocated 
    and a pointer to this is returned.  Otherwise, it is assumed that 
    the string \code{str} is large enough to hold the representation and 
    it is also the return value.

int _padic_fprint(FILE * file, const fmpz_t u, slong v, const padic_ctx_t ctx)

int padic_fprint(FILE * file, const padic_t op, const padic_ctx_t ctx)

    Prints the string representation of the $p$-adic number \code{op} 
    to the stream \code{file}.

    In the current implementation, always returns $1$.

int _padic_print(const fmpz_t u, slong v, const padic_ctx_t ctx)

int padic_print(const padic_t op, const padic_ctx_t ctx)

    Prints the string representation of the $p$-adic number \code{op} 
    to the stream \code{stdout}.

    In the current implementation, always returns $1$.

void padic_debug(const padic_t op)

    Prints debug information about \code{op} to the stream \code{stdout}, 
    in the format \code{"(u v N)"}.

