.. _padic:

**padic.h** -- p-adic numbers
===============================================================================


Introduction
--------------------------------------------------------------------------------

The ``padic_t`` data type represents elements of `\mathbf{Q}_p` to
precision `N`, stored in the form `x = p^v u` with `u, v \in \mathbf{Z}`.
Arithmetic operations can be carried out with respect to a context
containing the prime number `p` and various pieces of pre-computed data.

Independent of the context, we consider a `p`-adic number
`x = u p^v` to be in canonical form whenever either
`p \nmid u` or `u = v = 0`, and we say it is reduced
if, in addition, for non-zero `u`, `u \in (0, p^{N-v})`.

We briefly describe the interface:

The functions in this module expect arguments of type ``padic_t``,
and each variable carries its own precision.  The functions have an
interface that is similar to the MPFR functions.  In particular, they
have the same semantics, specified as follows:  Compute the requested
operation exactly and then reduce the result to the precision of the
output variable.

Data structures
--------------------------------------------------------------------------------

A `p`-adic number of type ``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.

.. function:: 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 ``fmpz`` functions.

.. function:: 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 ``padic_val(op)`` can be used as both an 
    *lvalue* and an *rvalue*.

.. function:: slong padic_get_val(const padic_t op)

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

.. function:: 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 ``padic_prec(op)`` can be used as both an 
    *lvalue* and an *rvalue*.

.. function:: 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 ``double`` 
inverse in case of word-sized primes, precomputed powers of `p` 
in the range given by ``min`` and ``max``, and the printing 
mode.

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

    Initialises the context ``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 ``min`` and ``max`` are non-negative and that 
    ``min`` is at most ``max``, raising an ``abort`` signal 
    otherwise.

    Assumes that the printing mode is one of ``PADIC_TERSE``, 
    ``PADIC_SERIES``, or ``PADIC_VAL_UNIT``.  Using the example 
    `x = 7^{-1} 12` in `\mathbf{Q}_7`, these behave as follows:

    In ``PADIC_TERSE`` mode, a `p`-adic number is printed 
    in the same way as a rational number, e.g. ``12/7``.

    In ``PADIC_SERIES`` mode, a `p`-adic number is printed 
    digit by digit, e.g. ``5*7^-1 + 1``.

    In ``PADIC_VAL_UNIT`` mode, a `p`-adic number is 
    printed showing the valuation and unit parts separately, 
    e.g. ``12*7^-1``.

.. function:: void padic_ctx_clear(padic_ctx_t ctx)

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

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

    Sets ``rop`` to `p^e` as efficiently as possible, where 
    ``rop`` is expected to be an uninitialised ``fmpz_t``.

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


Memory management
--------------------------------------------------------------------------------


.. function:: void padic_init(padic_t rop)

    Initialises the `p`-adic number with the precision set to 
    ``PADIC_DEFAULT_PREC``, which is defined as `20`.

.. function:: void padic_init2(padic_t rop, slong N)

    Initialises the `p`-adic number ``rop`` with precision `N`.

.. function:: void padic_clear(padic_t rop)

    Clears all memory used by the `p`-adic number ``rop``.

.. function:: void _padic_canonicalise(padic_t rop, const padic_ctx_t ctx)

    Brings the `p`-adic number ``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`.

.. function:: void _padic_reduce(padic_t rop, const padic_ctx_t ctx)

    Given a `p`-adic number ``rop`` in canonical form, 
    reduces it modulo `p^N`.

.. function:: void padic_reduce(padic_t rop, const padic_ctx_t ctx)

    Ensures that the `p`-adic number ``rop`` is reduced.


Randomisation
--------------------------------------------------------------------------------


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

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

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

    Sets ``rop`` to a random non-zero `p`-adic number modulo `p^N`, 
    where the range of the valuation is as for the function 
    :func:`padic_randtest`.

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

    Sets ``rop`` to a random `p`-adic integer modulo `p^N`.

    Note that whenever `N \leq 0`, ``rop`` is set to zero.


Assignments and conversions
--------------------------------------------------------------------------------

All assignment functions set the value of ``rop`` from ``op``, 
reduced to the precision of ``rop``.

.. function:: void padic_set(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Sets ``rop`` to the `p`-adic number ``op``.

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

    Sets the `p`-adic number ``rop`` to the 
    ``slong`` integer ``op``.

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

    Sets the `p`-adic number ``rop`` to the ``ulong`` 
    integer ``op``.

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

    Sets the `p`-adic number ``rop`` to the integer ``op``.

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

    Sets ``rop`` to the rational ``op``.

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

    Sets the `p`-adic number ``rop`` to the MPIR integer ``op``.

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

    Sets ``rop`` to the MPIR rational ``op``.

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

    Sets the integer ``rop`` to the exact `p`-adic integer ``op``.

    If ``op`` is not a `p`-adic integer, raises an ``abort`` signal.

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

    Sets the rational ``rop`` to the `p`-adic number ``op``.

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

    Sets the MPIR integer ``rop`` to the `p`-adic integer ``op``.

    If ``op`` is not a `p`-adic integer, raises an ``abort`` signal.

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

    Sets the MPIR rational ``rop`` to the value of ``op``.

.. function:: void padic_swap(padic_t op1, padic_t op2)

    Swaps the two `p`-adic numbers ``op1`` and ``op2``.

    Note that this includes swapping the precisions.  In particular, this 
    operation is not equivalent to swapping ``op1`` and ``op2`` 
    using :func:`padic_set` and an auxiliary variable whenever the 
    precisions of the two elements are different.

.. function:: void padic_zero(padic_t rop)

    Sets the `p`-adic number ``rop`` to zero.

.. function:: void padic_one(padic_t rop)

    Sets the `p`-adic number ``rop`` to one, reduced modulo the 
    precision of ``rop``.


Comparison
--------------------------------------------------------------------------------


.. function:: int padic_is_zero(const padic_t op)

    Returns whether ``op`` is equal to zero.

.. function:: int padic_is_one(const padic_t op)

    Returns whether ``op`` is equal to one, that is, whether 
    `u = 1` and `v = 0`.

.. function:: int padic_equal(const padic_t op1, const padic_t op2)

    Returns whether ``op1`` and ``op2`` are equal, that is, 
    whether `u_1 = u_2` and `v_1 = v_2`.


Arithmetic operations
--------------------------------------------------------------------------------


.. function:: slong * _padic_lifts_exps(slong *n, slong N)

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

    This function sets `n` and allocates and returns the array `a`.

.. function:: 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, 
    ``pow[i]`` is equal to `p^{a_i}`.

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

    Sets ``rop`` to the sum of ``op1`` and ``op2``.

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

    Sets ``rop`` to the difference of ``op1`` and ``op2``.

.. function:: void padic_neg(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Sets ``rop`` to the additive inverse of ``op``.

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

    Sets ``rop`` to the product of ``op1`` and ``op2``.

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

    Sets ``rop`` to the product of ``op`` and `p^v`.

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

    Sets ``rop`` to the quotient of ``op1`` and ``op2``.

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

.. function:: void _padic_inv_clear(padic_inv_t S)

    Frees the memory used by `S`.

.. function:: void _padic_inv_precomp(fmpz_t rop, const fmpz_t op, const padic_inv_t S)

    Sets ``rop`` to the inverse of ``op`` modulo `p^N`, 
    assuming that ``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 
    :func:`_padic_inv_precompute`.  Note that this object 
    is not declared ``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 :func:`padic_log`.

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

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

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

.. function:: void padic_inv(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Computes the inverse of ``op`` modulo `p^N`.

    Suppose that ``op`` is given as `x = u p^v`. 
    Raises an ``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`.

.. function:: int padic_sqrt(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Returns whether ``op`` is a `p`-adic square.  If this is 
    the case, sets ``rop`` to one of the square roots;  otherwise, 
    the value of ``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`.

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

    Sets ``rop`` to ``op`` raised to the power `e`, 
    which is defined as one whenever `e = 0`.

    Assumes that some computations involving `e` and the 
    valuation of ``op`` do not overflow in the ``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
--------------------------------------------------------------------------------


.. function:: 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 
    `\operatorname{ord}_p(x^j / j!) \geq N`, where `\operatorname{ord}_p(x) = v`.

    When `p` is a word-sized prime, 
    returns `\left\lceil \frac{(p-1)N - 1}{(p-1)v - 1}\right\rceil`.
    Otherwise, returns `\lceil N/v\rceil`.

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

.. function:: 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 ``rop`` to the `p`-exponential function evaluated at 
    `x = p^v u`, reduced modulo `p^N`.

    Assumes that `x \neq 0`, that `\operatorname{ord}_p(x) < N` and that 
    `\exp(x)` converges, that is, that `\operatorname{ord}_p(x)` is at least 
    `2` or `1` depending on whether the prime `p` is `2` or odd.

    Supports aliasing between ``rop`` and `u`.

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

    .. math ::


        \exp_p(x) = \sum_{i = 0}^{\infty} \frac{x^i}{i!}


    but this only converges only when `\operatorname{ord}_p(x) > 1 / (p - 1)`.  For 
    elements `x \in \mathbf{Q}_p`, this means that `\operatorname{ord}_p(x) \geq 1` 
    when `p \geq 3` and `\operatorname{ord}_2(x) \geq 2` when `p = 2`.

.. function:: 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}`.

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


.. function:: slong _padic_log_bound(slong v, slong N, const fmpz_t p)

    Returns `b` such that for all `i \geq b` we have 

    .. math ::


        i v - \operatorname{ord}_p(i) \geq N


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

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

    .. math ::

        z = - \sum_{i = 1}^{\infty} \frac{y^i}{i} \pmod{p^N},

    reduced modulo `p^N`.

    Note that this can be used to compute the `p`-adic logarithm 
    via the equation 

    .. math ::

        \log(x) & = \sum_{i=1}^{\infty} (-1)^{i-1} \frac{(x-1)^i}{i} \\
                & = - \sum_{i=1}^{\infty} \frac{(1-x)^i}{i}.

    Assumes that `y = 1 - x` is non-zero and that `v = \operatorname{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`.

.. function:: 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 ``op``, and if so sets ``rop`` to its 
    value.

    The `p`-adic logarithm function is defined by the usual series 

    .. math ::

        \log_p(x) = \sum_{i=1}^{\infty} (-1)^{i-1} \frac{(x-1)^i}{i}

    but this only converges when `\operatorname{ord}_p(x - 1)` is at least `2`
    or `1` when `p = 2` or `p > 2`, respectively.

.. function:: 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 ``op``, and if so sets ``rop`` to its 
    value.

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

.. function:: 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 ``op``, and if so sets ``rop`` to its 
    value.

    Uses an algorithm based on a result of Satoh, Skjernaa and Taguchi 
    that `\operatorname{ord}_p\bigl(a^{p^k} - 1\bigr) > k`, which implies that 

    .. math ::

        \log(a) \equiv p^{-k} \Bigl( \log\bigl(a^{p^k}\bigr) \pmod{p^{N+k}} 
                                                          \Bigr) \pmod{p^N}.


.. function:: 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 ``op``, and if so sets ``rop`` to its 
    value.


Special functions
--------------------------------------------------------------------------------


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

    Computes the Teichm\"uller lift of the `p`-adic unit ``op``, 
    assuming that `N \geq 1`.

    Supports aliasing between ``rop`` and ``op``.

.. function:: void padic_teichmuller(padic_t rop, const padic_t op, const padic_ctx_t ctx)

    Computes the Teichm\"uller lift of the `p`-adic unit ``op``.

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

    If ``op`` has negative valuation, raises an ``abort`` signal.

.. function:: ulong padic_val_fac_ui_2(ulong n)

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

    Note that since `n` fits into an ``ulong``, so does 
    `\operatorname{ord}_2(n!)` since `\operatorname{ord}_2(n!) \leq (n - 1) / (p - 1) = n - 1`.

.. function:: 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 ``ulong``, so does 
    `\operatorname{ord}_p(n!)` since `\operatorname{ord}_p(n!) \leq (n - 1) / (p - 1)`.

.. function:: void padic_val_fac(fmpz_t rop, const fmpz_t op, const fmpz_t p)

    Sets ``rop`` to the `p`-adic valuation of the factorial 
    of ``op``, assuming that ``op`` is non-negative.


Input and output
--------------------------------------------------------------------------------


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

    Returns the string representation of the `p`-adic number ``op``
    according to the printing mode set in the context.

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

.. function:: 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 ``op`` 
    to the stream ``file``.

    In the current implementation, always returns `1`.

.. function:: 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 ``op`` 
    to the stream ``stdout``.

    In the current implementation, always returns `1`.

.. function:: void padic_debug(const padic_t op)

    Prints debug information about ``op`` to the stream ``stdout``, 
    in the format ``"(u v N)"``.

