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

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

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

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

    Data structures

    A $p$-adic number $x$ in $\mathbf{Q}_p$ is stored internally 
    in the form $x = u p^v$, where $u$ is the unit part of $x$ 
    and $v$ is its valuation.

    We say such a number is in \emph{canonical} form if either 
    $u = v = 0$ or $p \nmid u$.

    When working modulo $p^N$, we say that the number is \emph{reduced} 
    if it is in canonical form and moreover, when $u \neq 0$, we have 
    that $0 < u < p^{N-v}$.

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

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.

    Note that this function is implemented as a macro.

long 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}.

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

    Context

    At the bare minimum, a context object for $p$-adic arithmetic 
    contains the prime number $p$, the precision $N$ and the 
    printing mode.

    In addition, various other useful objects may be stored in 
    the context, such as a pre-computed \code{double} inverse 
    of the prime $p$ or various powers of $p$ near $p^N$.

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

void padic_ctx_init(padic_ctx_t ctx, const fmpz_t p, long N, 
                    enum padic_print_mode mode)

    Initialises the context \code{ctx} with prime $p$, precision $N$, and 
    printing mode.

    Assumes that $p$ is a prime.

    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}

    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 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.

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

    N.B.  Expects \code{rop} to be an uninitialised \code{fmpz_t}.

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

    Memory management

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

void _padic_init(padic_t rop)

void padic_init(padic_t rop, const padic_ctx_t ctx)

    Initialises the $p$-adic number \code{rop}.

void _padic_clear(padic_t rop)

void padic_clear(padic_t rop, const padic_ctx_t ctx)

    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 
    with respect to the given context.

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

    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.

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()}.

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

    Assignments and conversions

    Between many data types there are two types of conversions, an 
    exact version presented in a function prefixed with an underscore 
    and a version modulo $p^N$.

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

void _padic_set(padic_t rop, const padic_t op)

    Sets \code{rop} to an exact copy of \code{op}.

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

    Sets \code{rop} to the value of \code{op} reduced modulo $p^N$.

void _padic_set_si(padic_t rop, long op, const padic_ctx_t ctx)

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

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

    Sets the $p$-adic number \code{rop} to the 
    \code{long} integer \code{op} reduced modulo $p^N$.

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

    Sets the $p$-adic number \code{rop} to the \code{unsigned long} 
    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{unsigned long} 
    integer \code{op} reduced modulo $p^N$.

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_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} 
    reduced modulo $p^N$.

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

    Sets \code{rop} to the rational \code{op} reduced 
    modulo $p^N$.

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_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} 
    reduced modulo $p^N$.

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} reduced 
    modulo $p^N$.

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, sets \code{rop} to zero.

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

    Sets the integer \code{rop} to the $p$-adic integer \code{op} 
    reduced modulo $p^N$.

    If \code{op} is not a $p$-adic integer, sets \code{rop} to zero.

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

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

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 integer \code{op} 
    reduced modulo $p^N$.

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

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

    If \code{op} is not a $p$-adic integer, sets \code{rop} to zero.

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}, 
    reduced modulo $p^N$.

    If \code{op} is not a $p$-adic integer, sets \code{rop} to zero.

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

    Sets the MPIR rational \code{rop} to the exact value of \code{op}.
    
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}, 
    reduced modulo $p^N$.

void padic_swap(padic_t op1, padic_t op2)

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

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.

void padic_one(padic_t rop, const padic_ctx_t ctx)

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

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

    Arithmetic operations

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

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

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

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} modulo $p^N$.

    Assumes that the input arguments are reduced modulo $p^N$ and 
    guarantees that the output will be, too.

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

    Sets \code{rop} to the exact difference 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} 
    modulo $p^N$.

    Assumes that the input arguments are reduced modulo $p^N$ and 
    guarantees that the output will be, too.

void _padic_neg(padic_t rop, const padic_t op)

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

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}.

    Assumes that the input arguments are reduced modulo $p^N$ and 
    guarantees that the output will be, too.

void _padic_mul(padic_t rop, const padic_t op1, const padic_t op2)

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

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}, 
    reduced modulo $p^N$.

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

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

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}, 
    reduced modulo $p^N$.

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

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

    Assumes that $N \geq 2$.

    This implies that $n = \ceil{\log_2 N} + 1 \geq 2$.

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, 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 pre-computed data $S$ that can be computed 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, long 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, long e, 
                  const padic_ctx_t ctx)

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

    Assumes that some computations involving $e$ and the 
    valuation of \code{op} do not overflow in the \code{long} 
    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$.

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

    Comparison

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

int _padic_is_zero(const padic_t op, const padic_ctx_t ctx)

    Returns whether \code{op} is zero.

int padic_is_zero(const padic_t op, const padic_ctx_t ctx)

    Returns whether \code{op} is zero modulo $p^N$.

int _padic_is_one(const padic_t op)

    Returns whether \code{op} is one.

int padic_is_one(const padic_t op, const padic_ctx_t ctx)

    Returns whether \code{op} is one modulo $p^N$.

int _padic_equal(const padic_t op1, const padic_t op2)

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

int padic_equal(const padic_t op1, const padic_t op2, const padic_ctx_t ctx)

    Returns whether \code{op1} and \code{op2} are equal modulo $p^N$.

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

    Special functions

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

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

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

    Assumes that $p$ is a prime and $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 abort signal.

void _padic_exp_naive(padic_t y, const padic_t x, const padic_ctx_t ctx)

    Returns the $p$-exponential function evaluated at \code{op}, 
    reduced modulo $p^N$.

    Assumes that $x \neq 0$ and that $\exp(x)$ converges.

void _padic_exp_rectangular(padic_t y, const padic_t x, const padic_ctx_t ctx)

    Returns the $p$-exponential function evaluated at \code{op}, 
    reduced modulo $p^N$.

    Assumes that $x \neq 0$ and that $\exp(x)$ converges.

void _padic_exp_balanced(padic_t y, const padic_t x, const padic_ctx_t ctx)

    Returns the $p$-exponential function evaluated at \code{op}, 
    reduced modulo $p^N$.

    Assumes that $x \neq 0$ and that $\exp(x)$ converges.

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$.

long _padic_log_bound(long v, long 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.

    Assumes that $N < 2^{f-2}$ where $f$ is \code{FLINT_BITS}.

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

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

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

void _padic_log_balanced(fmpz_t z, 
                         const fmpz_t y, long v, const fmpz_t p, long 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.

ulong padic_val_fac_ui2(ulong N)

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

ulong padic_val_fac_ui(ulong N, const fmpz_t p)

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

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

    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.

    Note that a negative unit part of \code{op} and the printing mode 
    \code{SERIES} are not compatible.

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}
    reduced modulo $p^N$, 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 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 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, const padic_ctx_t ctx)

    Prints debug information about \code{op} to the stream \code{stdout}.

