/*============================================================================= 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.