FLINT3.7.0-dev
Module · 123 functions

padic_radix.h

#include <flint/padic_radix.h>

This module implements Qp\mathbf{Q}_p for a word-size prime pp. An element is a ball pvu+O(pN)p^v u + O(p^N), or an exact element without error term, where the unit uu is a radix_integer_t whose limbs are digits in the radix B=peB = p^e (radix.h); the limb radix is chosen as large as possible, for example 7227^{22} for p=7p = 7 on a 64-bit machine. The valuation vv and the precision NN are counted in powers of pp, as in padic. Unlike padic, every function propagates the error terms of its inputs, so a result never claims more digits than are determined, and an exact computation stays exact as long as the result fits the precision of the context. Arithmetic on units is a truncation of limb arrays rather than a division, which makes the module several times faster than padic at high precision.

The module implements the generic ring interface (gr.h): the context is a gr_ctx_t, functions return the status flags GR_SUCCESS, GR_DOMAIN and GR_UNABLE, predicates return a truth_t, and polynomials, matrices and power series over Qp\mathbf{Q}_p are available as gr_poly, gr_mat and gr_series. The guide Getting started with padic_radix shows the precision model at work.

AlgorithmPrecision and representation of p-adic numbersHow FLINT represents a p-adic number as p^v u modulo p^N, the difference between absolute and relative precision, how much precision each arithmetic operation preserves, and the two precision models used by padic/qadic and by padic_radix.

Guides#

Precision#

A context has a default relative precision rr and absolute precision aa, either of which may be +∞+\infty (PADIC_RADIX_PREC_INF). Every result pvu+O(pN)p^v u + O(p^N) is truncated to the precision min⁡(N,a,v+r)\min(N, a, v + r), and an exact result is truncated only if it does not fit within min⁡(a,v+r)\min(a, v + r); a truncation is recorded in the error term. With a=+∞a = +\infty the arithmetic is floating-point-like with rr digits; with r=+∞r = +\infty it is fixed-point modulo pap^a, as in padic; with both infinite all arithmetic is exact in Z[1/p]\mathbb{Z}[1/p], and operations whose result would be an infinite expansion (such as 1/31/3) return GR_UNABLE. The error terms are propagated by the rules of Precision of arithmetic operations: the precision of a sum is the smaller absolute precision, that of a product, quotient or square root the smaller relative precision, adjusted by the valuations.

A nonzero unit is never divisible by pp; a zero unit has v=0v = 0. For an inexact element the unit is the nonnegative residue modulo pN−vp^{N - v}. Exact elements may have negative units only if the context has the flag PADIC_RADIX_SIGNED; otherwise a negative exact value is stored as an inexact residue if the context precision is finite.

Valuations and precisions may differ by up to about WORD_MAX / 2. In a context with a finite precision, the intermediate results of every operation are bounded in terms of the working precision (that of the context, or less when the inputs are less precise), whatever the exponents of the inputs: the fast algorithms for dot products, matrix and polynomial products and characteristic polynomials give up in favour of classical ones where their temporaries would be much larger than the precision of the outputs requires (see the individual functions). (With only an absolute precision aa, an element of valuation vv has a working precision of a−va - v digits, which is large for vv far below aa.) In a context without finite precision, the sizes are those of the exact results, which can be arbitrarily large (for example 1+pWORD_MAX/81 + p^{\mathrm{WORD\_MAX}/8}); they are bounded by the size_limit of the context, in digits (unlimited by default): exact results that would exceed it give GR_UNABLE, and inexact results keep at most size_limit digits of relative precision.

The value of NN that marks an exact element; it equals WORD_MAX.

The precision value +∞+\infty for the context parameters, equal to WORD_MAX.

The largest finite precision stored, WORD_MAX / 4. Larger precisions are clamped to it, which is always sound; valuations beyond ±\pmPADIC_RADIX_ERR_MAX and precisions below its negative cannot be represented, and the operations that would produce them return GR_UNABLE. The bound keeps sums of valuations and precisions from overflowing a slong.

Context#

int gr_ctx_init_padic_radix(gr_ctx_t ctx, ulong p, slong prec_rel, slong prec_abs, int flags)

Initialises ctx for Qp\mathbf{Q}_p with default relative precision prec_rel and absolute precision prec_abs, either of which may be PADIC_RADIX_PREC_INF, and the given combination of the flags below. Negative relative precisions are raised to 0, and finite precisions are clamped to ±\pmPADIC_RADIX_ERR_MAX. That pp is prime is only checked in builds with assertions. Returns GR_SUCCESS. The context is a field in the sense of gr_ctx_is_field, and is exact if and only if both precisions are infinite.

Context flags. PADIC_RADIX_SIGNED allows exact elements with negative units. PADIC_RADIX_NO_ERROR is reserved for a future floating-point mode without error terms and currently has no effect. PADIC_RADIX_DECIMAL prints units as decimal integers rather than in the default form of radix_get_str_sum. PADIC_RADIX_TEST_LIMITS makes padic_radix_randtest produce valuations and precisions near PADIC_RADIX_ERR_MAX. PADIC_RADIX_FAST_BOUNDS lets polynomial products use quasi-linear lower bounds for the precisions of the coefficients when the exact computation would cost more (irregular precision patterns in long products, see Matrix and polynomial products); the results may then have less precision than with the default exact bounds, never more. PADIC_RADIX_FAST_LINALG makes the linear algebra choose the fastest algorithms rather than those with the optimal precision, which is useful at high working precision, where losing a few digits costs less than the optimal algorithms: the characteristic polynomial uses the Hessenberg reduction (O(n3)O(n^3) operations, a few digits lost on structured matrices) instead of the exact lifting method or Berkowitz's algorithm (6 to 15 times faster for structured matrices at 1000 to 10000 digits and dimensions 30 to 80, losing up to 4 digits), and linear systems use the LU decomposition. Determinants are unaffected: their optimal algorithm is as fast as an LU decomposition. Results are valid either way.

Initialises ctx with a random prime and a random configuration for testing: absolute precision only, relative precision only, both (with precisions in [1,maxprec][1, \mathtt{maxprec}]) or neither, and random flags PADIC_RADIX_SIGNED, PADIC_RADIX_TEST_LIMITS and PADIC_RADIX_FAST_LINALG.

The data of a context: radix (the radix_struct for digit radix pp and limb radix pep^e), p, prec_abs, prec_rel and flags.

Pointer to the radix_struct used for the limb arithmetic of the context.

The precisions and flags of the context; the last two test single flags.

Implementations of gr_ctx_clear and gr_ctx_write; the description written has the form Radix 7-adic numbers (rel prec 10, abs prec inf).

Elements#

An element pvu+O(pN)p^v u + O(p^N): the fields are u (a radix_integer_struct), v and N, with N=N = PADIC_RADIX_EXACT for exact elements. A padic_radix_t is an array of one padic_radix_struct.

The unit (as a pointer), the valuation and the precision of x.

The following functions implement the generic ring methods; they are also accessible through the corresponding gr functions. All of them allow aliasing.

Initialise to the exact zero, clear, swap in constant time, and copy the structure without copying the limbs.

Return the precision NN of x (PADIC_RADIX_EXACT for an exact element), respectively whether x is exact.

Sets res to a random element with small valuation, exact or with a random error term (never with an error term in an exact context).

Writes x in the form (u) * p^v + O(p^N), omitting the power of pp when v=0v = 0 and the error term for exact elements, for example 188316833 + O(7^10). The unit is written by radix_get_str_sum, or as a decimal integer if the context has the flag PADIC_RADIX_DECIMAL. Strings of this form, including O(p^n), are accepted by gr_set_str.

Set res to the exact zero, respectively to one, which becomes 0+O(pt)0 + O(p^{t}) if t=min⁡(a,r)t = \min(a, r) is not positive for the context precisions aa and rr.

Sets res to x, truncated to the context precision.

Set res to the integer xx, truncated to the context precision. A negative xx in a context without PADIC_RADIX_SIGNED is stored as an inexact residue, or gives GR_UNABLE if the context precision is infinite.

Set res to the exact integer xx, ignoring the context precision; the unit may be negative regardless of the flags.

Sets res to the value of x if x is an exact integer. Returns GR_DOMAIN if v<0v < 0 and GR_UNABLE if x is inexact or its valuation exceeds the size limit of the context.

Set res to −x-x, x+yx + y, x−yx - y and xyxy. The error term of a sum is O(pmin⁡(Nx,Ny))O(p^{\min(N_x, N_y)}) and that of a product O(pmin⁡(Nx+vy,Ny+vx))O(p^{\min(N_x + v_y, N_y + v_x)}); the result is then truncated to the context precision. An exact zero factor gives an exact zero. An inexact zero O(pN)O(p^{N}) enters the error term of a product with valuation NN, so that for example O(pNx)⋅O(pNy)=O(pNx+Ny)O(p^{N_x}) \cdot O(p^{N_y}) = O(p^{N_x + N_y}).

Set res to xcxc, with the result of converting cc with padic_radix_set_si (etc.) followed by padic_radix_mul.

Set res to res±xy\mathrm{res} \pm xy (respectively ±xc\pm xc), with exactly the result of a multiplication into a temporary followed by an addition or subtraction. Product digits that cannot reach the result (above its precision) are not computed, and sums of at most two limbs are formed inline without temporaries.

Set res to xnx^n, computing the power of the unit with truncated multiplications and rounding once. For x=upv+O(pN)x = u p^v + O(p^N) and n≥1n \ge 1 the error term is O(p(n−1)v+N+vp(n))O(p^{(n - 1)v + N + v_p(n)}), which is valid since every term (nk)an−khk\binom{n}{k} a^{n - k} h^k, k≥1k \ge 1, of (a+h)n−an(a + h)^n - a^n has valuation at least (n−1)v+N+vp(n)(n - 1)v + N + v_p(n); for an inexact zero O(pN)O(p^N) it is O(pnN)O(p^{nN}). Negative exponents invert first. An exact input keeps an exact result when it fits the context precision.

Set res to 1/x1/x, respectively x/yx/y. The relative precision of the result is the smaller relative precision of the operands, capped by the context. Exact operands give an exact result when the quotient terminates (for example 1/491/49 or 6/36/3). Return GR_DOMAIN when dividing by an exact zero, and GR_UNABLE when the divisor is not known to be nonzero or when the context is exact and the quotient has an infinite expansion.

Returns whether x is nonzero: T_TRUE if it is exact and nonzero or its leading digit is known, T_FALSE for an exact zero and T_UNKNOWN otherwise.

Set res to a square root x\sqrt x, respectively 1/x1/\sqrt x, with relative precision equal to that of xx (one digit less for p=2p = 2), capped by the context. The root is a fixed canonical branch, so that a result at lower precision is the truncation of the result at higher precision, and rsqrt gives the reciprocal of sqrt. An exact perfect square gives its exact root. Return GR_DOMAIN if xx has odd valuation or its unit is not a square (and for rsqrt if xx is an exact zero), and GR_UNABLE if xx is not known to be nonzero, if p=2p = 2 and the unit is known to fewer than 3 digits, or if the context is exact and the root is irrational. sqrt of an exact zero is zero.

Returns whether xx is a square: decided by the valuation and the unit modulo pp (modulo 8 for p=2p = 2), and T_UNKNOWN for an inexact zero or, for p=2p = 2, a unit known to fewer than 3 digits.

Elementwise resi=vecic\mathrm{res}_i = \mathrm{vec}_i c and resi=resi±vecic\mathrm{res}_i = \mathrm{res}_i \pm \mathrm{vec}_i c, with the results of the corresponding scalar functions; the scalar is converted once.

Ball predicates: T_TRUE only for exact elements with the property, T_FALSE if no value in the ball has it (for equality, if the balls are disjoint), and T_UNKNOWN otherwise.

Dot products#

int padic_radix_dot_strided(padic_radix_t res, const padic_radix_t initial, int subtract, const padic_radix_struct * vec1, slong stride1, const padic_radix_struct * vec2, slong stride2, slong len, gr_ctx_t ctx)
int padic_radix_dot_strided_naive(padic_radix_t res, const padic_radix_t initial, int subtract, const padic_radix_struct * vec1, slong stride1, const padic_radix_struct * vec2, slong stride2, slong len, gr_ctx_t ctx)
int padic_radix_dot_strided_delayed(padic_radix_t res, const padic_radix_t initial, int subtract, const padic_radix_struct * vec1, slong stride1, const padic_radix_struct * vec2, slong stride2, slong len, gr_ctx_t ctx)

Set res to s±∑i<lenaibis \pm \sum_{i < len} a_i b_i with aia_i = vec1[i * stride1], bib_i = vec2[i * stride2], ss = initial (zero if initial is NULL) and the sign −- if subtract is nonzero. The naive version calls padic_radix_mul and padic_radix_add in a loop. The delayed version finds the minimum valuation and the precision of the result first, then accumulates the limb products of all terms in three-word accumulators, grouped by the residue of the digit offset modulo ee and by sign; at the end the residue classes are combined in one pass (each accumulator multiplied by prp^r for its residue rr) and the carries are propagated once. The default uses the naive version for at most 4 terms at a precision of one limb, 3 terms at two limbs and 2 terms above (relative precision, or absolute if there is none), and, at precisions of up to two limbs, also for up to 7 terms whose valuations v(ai)+v(bi)v(a_i) + v(b_i) are not all equal.

When all terms are exact, the delayed version keeps the result exact if it fits in the context precision (as padic_radix_mul and padic_radix_add do), provided that the a priori extent of the terms, max⁡i(v(ai)+e∣ai∣+v(bi)+e∣bi∣)\max_i (v(a_i) + e |a_i| + v(b_i) + e |b_i|) for units of ∣ai∣|a_i| and ∣bi∣|b_i| limbs, is at most one limb beyond the context precision; otherwise the sum is rounded to the context precision. In a context without finite precision, when the window of the delayed version (the extent of the exact terms, or the precision they determine) exceeds the size_limit of the context, it calls the naive version, which builds only the partial sums (and still gets exact cancellations of terms with huge valuations right).

int padic_radix_dot(padic_radix_t res, const padic_radix_t initial, int subtract, const padic_radix_struct * vec1, const padic_radix_struct * vec2, slong len, gr_ctx_t ctx)
int padic_radix_dot_rev(padic_radix_t res, const padic_radix_t initial, int subtract, const padic_radix_struct * vec1, const padic_radix_struct * vec2, slong len, gr_ctx_t ctx)

The contiguous dot product and the dot product with vec2 reversed, as wrappers of padic_radix_dot_strided. These implement the generic dot product methods, which gr_mat_mul and the gr_poly products use.

Matrix and polynomial products#

The block products use a packed limb-aligned form internally: an element upvu p^v is stored relative to the limb frame w=⌊v/e⌋w = \lfloor v/e \rfloor as the residue upv−ew mod BLu p^{v - ew} \bmod B^L, so that all terms of an output land at whole-limb offsets of a single accumulator, without digit shifts. Each input is converted once, the precision of every output is computed up front from arrays of exponents (min-plus products or convolutions), and at precisions of up to two limbs the accumulation runs in registers. Every output is computed with exactly the semantics of padic_radix_dot_strided_delayed (the same precision, and the same value modulo it, including exact sums of exact terms). The packed versions return GR_UNABLE without modifying the output when they do not apply: in contexts without a finite precision (where exact results need full products) and for elements with exponents beyond ±WORD_MAX/16\pm\mathrm{WORD\_MAX}/16.

int padic_radix_mat_mul(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)

Set C=ABC = AB. The packed version accumulates the limb products of every output directly. The fmpz version scales row ii of AA and column jj of BB to base frames ri=min⁡tw(Ait)r_i = \min_t w(A_{it}) and cj=min⁡tw(Btj)c_j = \min_t w(B_{tj}), truncates the residues to the largest output window, multiplies the resulting integer matrices with nmod_mat_mul (modulo BB, when every window is a single limb) or fmpz_mat_mul (multimodular and blocked algorithms), and reduces every output modulo BsB^s for its window of ss limbs before the conversion to radix BB. The mpn_mod version is the same with the products done modulo BSB^S for the largest window of SS limbs by mpn_mod_mat_mul (classical with delayed reduction, Waksman or multimodular), and returns GR_UNABLE if BSB^S does not have between 2 and MPN_MOD_MAX_LIMBS binary limbs; padic_radix_mat_mul uses it in that range, the nmod version for one-limb windows and the fmpz version above. Outputs whose terms are all exact are summed exactly, in windows covering the a priori extents of their terms plus a carry and a sign limb, when padic_radix_dot_strided_delayed would keep them exact. Its precisions are computed with blockwise minima of the exponents, in O(mn⋅blocks)O(mn \cdot \text{blocks}) operations for outputs whose row of AA or column of BB has exponents that are constant on blocks of the inner index (e.g. uniform valuations and precisions), and with the exact O(k)O(k) minimum for the others; the results are identical to those of the packed version. The base frames ri+cjr_i + c_j can be far below the frame of an output whose terms all have higher valuations; the fmpz and mpn_mod versions return GR_UNABLE when the largest window in the base frames exceeds four times (plus 8 limbs) the largest window of an output in its own frame, since the integers would then be much larger than the precision requires (arbitrarily large for valuations spread beyond the precision).

padic_radix_mat_mul implements the generic method gr_mat_mul: the classical algorithm for inner dimension at most 3, the modular versions above tuned crossovers (estimated from an upper bound for the output windows: from dimension 8 when all windows are one limb, about 32 at two limbs, 16 at 3 to 8 limbs, 28 up to 15 limbs and 48 beyond, raised when the limb frames of the entries are spread out and when the exact precision bookkeeping is needed), and the packed version otherwise.

int _padic_radix_poly_mulmid_KS(padic_radix_struct * res, const padic_radix_struct * poly1, slong len1, const padic_radix_struct * poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
int _padic_radix_poly_mulmid_mod(padic_radix_struct * res, const padic_radix_struct * poly1, slong len1, const padic_radix_struct * poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)

Middle product by Kronecker substitution in radix BB: the coefficients, scaled to the base frames of the two polynomials and truncated to the largest output window of SS limbs, are placed in slots of 2S+O(1)2S + O(1) limbs of a single radix integer, and one radix_mulmid (which uses the small-prime FFT directly in radix BB for large operands, without conversions to binary) gives every output in its own slot. The mod version instead multiplies the residues modulo BSB^S, avoiding the padding of the slots: with _nmod_poly_mulmid when S=1S = 1 and with _mpn_mod_poly_mulmid (classical, Karatsuba or the small-prime FFT, as tuned for mpn_mod) when BSB^S has at most MPN_MOD_MAX_LIMBS binary limbs, converting to binary and back; otherwise it returns GR_UNABLE. The output precisions come from min-plus convolutions of the exponent sequences (below), and coefficients whose terms are all exact are summed exactly (in windows covering the extents of the terms) when padic_radix_dot_strided_delayed would keep them exact. The results are those of _padic_radix_poly_mulmid_packed, except with the context flag PADIC_RADIX_FAST_BOUNDS, which allows smaller (but never larger) precisions. Both return GR_UNABLE in the same cases as the packed version. Outputs whose window in the base frames exceeds four times (plus 8 limbs) the largest window of an output in its own frame (all of whose terms have valuations far above the base frames, e.g. next to a few coefficients of huge valuation) are computed separately by padic_radix_dot_strided_delayed when there are few of them (costing at most about the transform and a sixteenth of the classical algorithm); otherwise, that is when the valuations vary beyond the precision along the outputs (alternating, trending or random valuations spread over more digits than the precision), both return GR_UNABLE. High-valuation coefficients that are beyond the precision of every output they contribute to cost nothing.

The per-coefficient precisions of a polynomial product are min-plus convolutions ck=min⁡i(ai+bk−i)c_k = \min_i (a_i + b_{k-i}) of exponent sequences, with +∞+\infty for absent terms (exact zeros, or exact coefficients in the error terms). They are always computed exactly by default:

  • directly, over the pairs of finite entries only, when there are few of these (sparse sequences, e.g. with exact zero padding, cost only the number of pairs);
  • by the lower convex hulls (the Minkowski sum of their slopes, in linear time) when both sequences are convex without gaps (in particular constant or linear: uniform valuations and precisions);
  • by bivariate Kronecker substitution when, after subtracting a common linear trend, the finite values span a small range RR: the minimum is the lowest power of yy present in the coefficient of xkx^k in (∑ixiyai)(∑jxjybj)(\sum_i x^i y^{a_i})(\sum_j x^j y^{b_j}), which one integer multiplication of O(nRlog⁡n)O(nR \log n) bits provides;
  • otherwise by bands of values: with the values split into 32 bands, the convolution is the minimum over the pairs of bands of the convolutions restricted to those bands, each done directly or by Kronecker substitution over the actual range of values of the band (small for clustered values: block-dependent precisions, alternating or periodic patterns). The pairs are processed by increasing sum of the band levels, so that outputs become final as soon as their current value is below the level of the remaining pairs, and pairs whose output range only contains final outputs (or outputs without any finite term) are skipped.

The cost is linear or quasi-linear in the regular cases and at most about that of the quadratic algorithm (often much less, thanks to the early termination) for irregular ones. With PADIC_RADIX_FAST_BOUNDS, when the exact computation would cost more than a Kronecker substitution of range 64, the result may instead be a lower bound: the maximum of the convex hull bound and the Kronecker substitution on values rounded down to multiples of δ=⌈R/64⌉\delta = \lceil R / 64 \rceil (within 2δ2\delta), with the outputs near the ends computed exactly and those without finite terms recognised exactly.

int _padic_radix_poly_mulmid_packed(padic_radix_struct * res, const padic_radix_struct * poly1, slong len1, const padic_radix_struct * poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
int _padic_radix_poly_mulmid(padic_radix_struct * res, const padic_radix_struct * poly1, slong len1, const padic_radix_struct * poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
int _padic_radix_poly_mullow(padic_radix_struct * res, const padic_radix_struct * poly1, slong len1, const padic_radix_struct * poly2, slong len2, slong n, gr_ctx_t ctx)

Set res to the coefficients nlo,…,nhi−1n_{lo}, \ldots, n_{hi} - 1 (respectively 0,…,n−10, \ldots, n - 1) of the product of the polynomials. Coefficients that are a single product are computed with padic_radix_mul. The unpacked versions implement the generic methods. For both lengths at least 4, from an estimate SS of the output windows in limbs (the size of the units, plus one if the valuations are not multiples of ee, plus the spread of the limb frames): the mod version when S=1S = 1; for S=2S = 2 from a length of about 64, for S≤10S \le 10 from about 24, and the radix KS version for S>10S > 10 from about 32 (these crossovers raised when the frames are spread out); the packed version otherwise. Before choosing a Kronecker substitution route when the frames are spread out, the windows of 16 sampled outputs are estimated from the context precision, and the packed version is used if the base frames inflate at least three of them as above; if a route still gives up, the packed version is used without trying the other. Shorter products use the classical algorithm.

Linear algebra#

int padic_radix_mat_find_nonzero_pivot(slong * pivot_row, gr_mat_t mat, slong start_row, slong end_row, slong column, gr_ctx_t ctx)

Implements the generic method gr_mat_find_nonzero_pivot, used by the generic LU decomposition, solving, inversion and reduced row echelon form algorithms: chooses a row whose entry in the given column has minimal valuation, so that the elimination only involves multipliers of nonnegative valuation. Returns GR_UNABLE if there is no nonzero entry but some inexact zero, and GR_DOMAIN if all entries are exact zeros.

Set res to the determinant of the square matrix A. The lu_full version uses Gaussian elimination with full pivoting on valuations (an entry of minimal valuation in the whole remaining submatrix). Then the multipliers and the pivot rows have valuations at least that of the pivot, the Schur complements keep the absolute precision of the input, and the pivots have the valuations a1≤⋯≤ana_1 \le \cdots \le a_n of the elementary divisors. For a matrix with entries known to O(pN)O(p^N) (and an<Na_n < N) the determinant is obtained to precision N+a1+⋯+an−1N + a_1 + \cdots + a_{n-1}, which is optimal: it is that of the differential ddet⁡(A)=tr⁡(adj⁡(A) dA)d \det(A) = \operatorname{tr}(\operatorname{adj}(A)\, dA). In comparison, division-free algorithms (Berkowitz, cofactor expansion) only give precision about NN, losing up to v(det⁡A)−anv(\det A) - a_n digits, and Gaussian elimination with the first nonzero pivot loses precision growing with the dimension for small pp, even for generic matrices (about 19 digits at n=60n = 60 for p=7p = 7). If the remaining submatrix consists of zeros, the determinant of that block is bounded using the sums of the row and column minima of the precisions.

The levels version is a blocked form of full pivoting. At the minimal valuation aa of the current Schur complement SS, a rank-revealing LU decomposition of (S/pa) mod p(S / p^a) \bmod p over Fp\mathbb{F}_p selects rr rows and columns such that S11=paUS_{11} = p^a U with UU invertible modulo pp: these rr pivots all have valuation aa, as in full pivoting, and are eliminated at once, with det⁡S=±det⁡(S11)det⁡(S22−S21S11−1S12)\det S = \pm \det(S_{11}) \det(S_{22} - S_{21} S_{11}^{-1} S_{12}), using the LU decomposition of S11S_{11}, triangular solves and one matrix product. The new Schur complement has entries of valuation at least a+1a + 1. The precision is again optimal, and the cost is that of a blocked LU decomposition (a single level for a matrix invertible modulo pp).

padic_radix_mat_det implements the generic method gr_mat_det: the cofactor formula for n≤2n \le 2, the lu_full version up to a dimension depending on the precision (40 at one limb, 24 at two limbs, 16 beyond), and the levels version above.

Set X=A−1BX = A^{-1} B (respectively X=A−1X = A^{-1}), returning GR_DOMAIN if AA is singular and GR_UNABLE if this cannot be decided. The algorithm is Gauss-Jordan elimination with full pivoting by valuation levels on [A∣B][A \mid B]: at each level the pivot block (as in padic_radix_mat_det_levels) is applied to its rows, and its columns are eliminated from all the other rows, including the pivot rows of the previous levels, with one matrix product. This order of operations (that of Gauss-Jordan elimination with full pivoting) gives every entry of the solution with the optimal precision, that of the differential dX=A−1(dB−dA X)dX = A^{-1}(dB - dA\, X); LU decompositions with column pivots and back substitution lose some digits when AA is not invertible modulo pp. When A/paA / p^a is invertible modulo pp for the minimal valuation aa of its entries, all pivots have valuation aa and the generic LU solve (with the pivots of padic_radix_mat_find_nonzero_pivot) is used directly, as it is always with the context flag PADIC_RADIX_FAST_LINALG. These functions implement the generic methods gr_mat_nonsingular_solve and gr_mat_inv.

Set cp to the characteristic polynomial χ(x)=det⁡(xI−A)\chi(x) = \det(xI - A) of the square matrix mat.

The berkowitz version is the division-free Berkowitz algorithm, with the matrix-vector products done on the matrix packed once (falling back to _gr_mat_charpoly_berkowitz for dimension at most 5, in contexts without a relative precision, and for matrices with exact nonzero entries). For integral entries known to O(pN)O(p^N) it gives every coefficient to precision about NN, which is optimal when the matrix is cyclic modulo pp but can lose many digits otherwise (dozens for the low coefficients of moderately structured matrices of dimension 16).

The hessenberg version reduces the matrix to Hessenberg form by similarity transformations with pivots of minimal valuation (so that the transformations are in GLn(Zp)\mathrm{GL}_n(\mathbb{Z}_p)), in O(n3)O(n^3) operations; it loses a few digits.

The lift version gives the optimal precision. With the matrix scaled by a power of pp to make it integral, MM the exact lift of the entries and adj⁡(xI−M)=∑kBkxk\operatorname{adj}(xI - M) = \sum_k B_k x^k, a perturbation EE with v(Eij)≥Nijv(E_{ij}) \ge N_{ij} changes ckc_k by −tr⁡(BkE)-\operatorname{tr}(B_k E) plus terms of order at least two in EE, whose coefficients (minors of xI−MxI - M) are integral. Hence ck(A)=ck(M)+O(pNk)c_k(A) = c_k(M) + O(p^{N_k}) with Nk=min⁡(2Nmin⁡,min⁡ij(Nij+v((Bk)ji)))N_k = \min(2 N_{\min}, \min_{ij} (N_{ij} + v((B_k)_{ji}))), the precision of the differential of χ\chi. The coefficients ck(M)c_k(M) are computed modulo p2Nmin⁡p^{2 N_{\min}} by the hessenberg version at a raised working precision (retried with more digits if needed, with the berkowitz version as a last resort), and the BkB_k by the recurrence Bn−1=IB_{n-1} = I, Bk−1=MBk+ckIB_{k-1} = M B_k + c_k I, modulo one word first and modulo pNmin⁡p^{N_{\min}} if valuations at that bound matter, with nn matrix products. Exact matrices give the exact characteristic polynomial (multimodular), rounded to the context precision.

The lifted entries are reduced modulo the largest working precision, so that entries of high valuation cost nothing. The working precision 2(Nmin⁡+s)2(N_{\min} + s), where psp^s is the scaling, is large when an entry has a much smaller valuation (or error term) than the others; the lift version returns GR_UNABLE when Nmin⁡+s>64(R+n)+1024N_{\min} + s > 64(R + n) + 1024, where RR is the largest relative precision of an inexact entry. For exact matrices it returns GR_UNABLE when the exact characteristic polynomial would exceed the size_limit of the context, when the entries of MM have more than 4r+2564 r + 256 digits for a finite context precision rr, or when they are dominated by powers of pp (valuations above four times the size of the units plus 256 digits), which Berkowitz's algorithm in Qp\mathbf{Q}_p handles without expanding them.

padic_radix_mat_charpoly implements the generic method. For matrices with integral entries of uniform precision NN that are cyclic modulo pp (tested with a random Krylov basis over Fp\mathbb{F}_p), the optimal precision is NN for every coefficient: the hessenberg version is tried first and accepted if it attains it (as for matrices that are generic modulo pp), and otherwise the berkowitz version, which always does, is used. Other matrices use the lift version, together with Danilevsky's algorithm (keeping the more precise result for each coefficient) where the bound 2Nmin⁡2 N_{\min} limits it, and the berkowitz version when the lift version gives up. With the context flag PADIC_RADIX_FAST_LINALG, the hessenberg version is used for all matrices.

Exponential and logarithm#

The algorithms are those of padic.h in radix arithmetic; see The p-adic exponential and logarithm.

Returns the number nn of terms after which the exponential series for an argument of valuation vv can be truncated modulo pNp^N, n=max⁡(1,⌈((p−1)N−1)/((p−1)v−1)⌉)n = \max(1, \lceil ((p-1)N - 1)/((p-1)v - 1) \rceil). Assumes that the series converges (v≥1v \ge 1, or v≥2v \ge 2 for p=2p = 2).

void _padic_radix_exp(radix_integer_t rop, const radix_integer_t u, slong v, slong N, const radix_t radix)

Set rop to the nonnegative residue of exp⁡(upv)\exp(u p^v) modulo pNp^N, for v≥1v \ge 1 (v≥2v \ge 2 if p=2p = 2), not checked. The rectangular version uses rectangular splitting, the balanced version the pp-adic bit-burst method with binary splitting. _padic_radix_exp uses the rectangular version for NN below a cutoff between 80 and 200 that decreases with the size of pp.

Set res to exp⁡(x)\exp(x), with precision min⁡(Nx,a,r)\min(N_x, a, r) for the context precisions aa and rr (the result is a unit). Return GR_DOMAIN if the series diverges, and GR_UNABLE if convergence cannot be decided (an inexact zero of too low precision) or the context precision is infinite.

Returns the least b≥2b \ge 2 such that iv−ord⁡p(i)≥Niv - \operatorname{ord}_p(i) \ge N for all i≥bi \ge b, so that the series for log⁡(1−y)\log(1 - y) with ord⁡p(y)=v\operatorname{ord}_p(y) = v can be truncated after b−1b - 1 terms.

void _padic_radix_log(radix_integer_t rop, const radix_integer_t y, slong N, const radix_t radix)

Set rop to the residue of log⁡(1−y)\log(1 - y) modulo pNp^N for an integer yy of valuation at least 1 (not checked). _padic_radix_log uses the rectangular version for NN below a cutoff between 80 and 350 that decreases with the size of pp.

Set res to log⁡(x)\log(x), with absolute precision min⁡(Nx,a,r)\min(N_x, a, r). Return GR_DOMAIN unless x≡1(modp)x \equiv 1 \pmod p (for every pp, including p=2p = 2), and GR_UNABLE if this cannot be decided or if xx is exact and the context precision infinite.

Internal functions#

Canonicalises a freshly computed element (moving factors of pp from the unit to the valuation), enforces the representability bounds of PADIC_RADIX_ERR_MAX and truncates to the context precision. Returns GR_UNABLE if the valuation or precision cannot be represented, in which case res is set to O(p−ERR_MAX)O(p^{-\mathrm{ERR\_MAX}}) so that further arithmetic on it stays within the representable range.

Simple reference implementations of addition (x+yx + y, or x−yx - y if sub is nonzero) and multiplication, used to test the optimised functions.

Cite this page

The FLINT team, “padic_radix.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/padic_radix/index.html (generated 2026-11-02).