FLINT3.7.0-dev
Module · 201 functions

fft_small.h

#include <flint/fft_small.h>

This module multiplies large integers, and polynomials over \mathbb{Z}/n\mathbb{Z} and \mathbb{Z}, with number-theoretic transforms modulo a few 50-bit primes p with p - 1 divisible by a large power of two. The residues are stored as integers in double variables and all modular arithmetic is done in floating point with fused multiply-add, on vectors of four or eight doubles. Products whose coefficients exceed one prime are computed modulo up to eight primes and reconstructed with the Chinese remainder theorem.

The module is compiled only on 64-bit targets with AVX2 (x86-64) or NEON (ARM64), where FLINT_HAVE_FFT_SMALL is 1; on other targets the header declares only FLINT_FFT_SMALL_ALIGNMENT and flint_fft_small_max_transformed_ring_size, and FLINT multiplies large integers with GMP's mpn_mul and, from 32000 limbs, the Schönhage–Strassen code instead.

Most programs use the module indirectly. flint_mpn_mul calls it for operands of a few hundred limbs and more, and nmod_poly_mul, fmpz_poly_mul and their truncated and middle-product variants call it for long polynomials; the guide Where FLINT uses fft_small lists every caller and its thresholds. The functions below are for code that wants to bypass those dispatchers, reuse a transformed operand (for polynomials, or for integers that are multiplied by a common factor), accumulate several products in transform space (Arithmetic in transform space), or compute middle products as transposed products.

Guides#

Conventions#

  • B = 2^{\mathtt{FLINT\_BITS}}, and a limb is one ulong. Integers are given as limb arrays, least significant limb first, as in GMP's mpn layer.
  • Polynomials are coefficient arrays, constant term first. A window [z_l, z_h) of a product c = ab of lengths a_n and b_n means the coefficients c_{z_l}, \ldots, c_{z_h - 1}, where coefficients of index a_n + b_n - 1 and beyond are zero. Windows give full, low (mullow) and middle products with one function.
  • Over \mathbb{Z}/n\mathbb{Z}, coefficients must be reduced modulo n.
  • Functions with an mpn_ctx_t argument take their primes, tables and scratch memory from it. The functions with default in their name use the context returned by get_default_mpn_ctx, which is local to the calling thread. A context must not be used by two threads at the same time; the functions themselves spread their work over the threads of FLINT's thread pool (flint_set_num_threads).
  • Unless stated otherwise, outputs must not overlap inputs.

Contexts#

A multiplication context. It holds the transform contexts of MPN_CTX_NCRTS = 8 primes, the Chinese remaindering data for the first k of them for every k \le 8, tables of powers of two modulo each prime for converting integers, the table of packing profiles, the constants of the two-prime pipeline, and a scratch buffer that grows on demand and is kept between calls.

More

Initialises R from the initial prime p and frees it. FLINT itself always uses p = 63 \cdot 2^{44} + 1 (0x0003f00000000001), the value get_default_mpn_ctx passes.

More

Returns the default context of the calling thread, creating it on the first call. flint_cleanup and flint_cleanup_master free it.

Returns at least n bytes of scratch memory from the context, aligned to 4096 bytes. The memory belongs to the context and must not be freed. A later call may move the buffer, so the pointer is valid only until the next call on R, and only one request can be outstanding.

More

Reserves the tail of the scratch buffer: the buffer is grown to hold head plus tail bytes (each rounded up to 4096), and the returned pointer to the last tail bytes stays valid until the release. Returns NULL if a reservation is already live. Reserving, like any growth, invalidates a pointer returned by mpn_ctx_fit_buffer.

More

Integer multiplication#

The integers are cut into chunks of a fixed number of bits, the chunk sequences are multiplied as polynomials modulo two to eight primes, and the product is reassembled with carries. Up to 40000 limbs, two primes and chunks of 40 to 45 bits are used; above, four to eight primes and chunks of 84 to 192 bits, chosen from a table of profiles.

void mpn_ctx_mpn_mul(mpn_ctx_t R, ulong * z, const ulong * a, ulong an, const ulong * b, ulong bn)

Sets (z, a_n + b_n) to the product of (a, a_n) and (b, b_n), using R or the default context. Requires a_n, b_n \ge 1, in either order. If a == b and a_n = b_n, a square is computed.

Full documentation
void _mpn_ctx_mpn_mul_range(mpn_ctx_t R, ulong * z, ulong lo, ulong hi, const ulong * a, ulong an, const ulong * b, ulong bn)

Writes to (z, \mathit{hi} - \mathit{lo}) the limbs [\mathit{lo}, \mathit{hi}) of the product of (a, a_n) and (b, b_n). The result is exact for \mathit{lo} = 0; otherwise carries from below limb \mathit{lo} may be lost, making it smaller than the exact window by a few units. Limbs at or above a_n + b_n are zero.

Full documentation

Integer products with a common operand#

When several products share an operand, its transform can be computed once. _fft_small_mpn_mul_shared forms two products ax and bx, and the _fft_small_mpn_mul_precomp functions keep the transform of a fixed factor x for any number of products. flint_mpn_mul_shared chooses between the first and two ordinary products. See Integer products with a common operand.

Sets (z_1, a_n + x_n) to ax and (z_2, b_n + x_n) to bx, computing the transform of x once: three forward and two inverse transforms instead of four and two. Requires a_n, b_n, x_n \ge 1, in any order of size. z1 may overlap a and x but not b; z2 may overlap any input but not z1.

Full documentation

The transform of a fixed integer x of xn limbs for products with partners of up to yn_max limbs: the transform data d, xstride doubles per prime, and the geometry, either two-prime (chunk size bits and depth) or, if wide is set, given by the plan P. owns records whether d was allocated by the initialisation.

Full documentation

_fft_small_mpn_mul_precomp_size returns the number of doubles that the transform of an integer of x_n limbs needs for partners of up to yn_max limbs. _fft_small_mpn_mul_precomp_init stores the transform of (x, x_n) in storage, which must hold that many doubles and be aligned to 32 bytes, or in memory it allocates if storage is NULL. _fft_small_mpn_mul_precomp_clear frees that memory, but not storage provided by the caller. Require x_n, \mathtt{yn\_max} \ge 1.

Full documentation

Sets (z, x_n + y_n) to xy, where x is the integer whose transform P holds. Requires 1 \le y_n \le yn_max; z may overlap y.

Full documentation

Polynomial multiplication#

Products of polynomials over \mathbb{Z}/n\mathbb{Z} and \mathbb{Z}, as windows of the full product, and transposed products over \mathbb{Z}/n\mathbb{Z}, which give middle products at the cost of a product of the output length. The coefficients of the integer product are computed modulo as many primes as their size requires and reconstructed by the Chinese remainder theorem.

void _nmod_poly_mul_mid_mpn_ctx(ulong * z, ulong zl, ulong zh, const ulong * a, ulong an, const ulong * b, ulong bn, nmod_t mod, mpn_ctx_t R)

Sets (z, z_h - z_l) to the coefficients [z_l, z_h) of the product of (a, a_n) and (b, b_n) modulo n. Requires a_n, b_n \ge 1, in either order, and reduced coefficients; any modulus n \ge 1 is allowed.

Full documentation
void _nmod_poly_mul_tr_mpn_ctx(ulong * z, ulong zn, const ulong * a, ulong an, const ulong * v, ulong vn, nmod_t mod, mpn_ctx_t R)

Transposed product: sets z_j = \sum_i a_i v_{i+j} \bmod n for 0 \le j < z_n, with (v, v_n) read as padded with zeros to length a_n + z_n - 1. This is the transpose of the multiplication by (a, a_n) of polynomials of length z_n; with a the reversal of f it is the window [a_n - 1, a_n - 1 + z_n) of the product fv. Requires a_n, v_n, z_n \ge 1, v_n \le a_n + z_n - 1 and reduced coefficients; the output must not overlap the inputs.

Full documentation
int _fmpz_poly_mul_mid_mpn_ctx(fmpz * z, ulong zl, ulong zh, const fmpz * a, ulong an, const fmpz * b, ulong bn, mpn_ctx_t R)
int _fmpz_poly_mul_mid_default_mpn_ctx(fmpz * z, slong zl, slong zh, const fmpz * a, slong an, const fmpz * b, slong bn)

Sets (z, z_h - z_l) to the coefficients [z_l, z_h) of the product of (a, a_n) and (b, b_n) over \mathbb{Z} and returns 1, if eight primes suffice for the coefficient size; otherwise returns 0 and leaves z unchanged. Requires a_n, b_n \ge 1; z must hold initialised fmpz values.

Full documentation
void _nmod_poly_divrem_mpn_ctx(ulong * q, ulong * r, const ulong * a, ulong an, const ulong * b, ulong bn, nmod_t mod, mpn_ctx_t R)

Sets (q, a_n - b_n + 1) and (r, b_n - 1) to the quotient and remainder of (a, a_n) divided by (b, b_n) modulo n. Requires a_n \ge b_n \ge 2 and an invertible leading coefficient of b.

More
void _nmod_poly_mul_mid(ulong * z, slong zl, slong zh, const ulong * a, slong an, const ulong * b, slong bn, nmod_t mod)
void _nmod_poly_mul_mid_classical(ulong * z, slong zl, slong zh, const ulong * a, slong an, const ulong * b, slong bn, nmod_t mod)

Reference implementations of the window product without transforms, used by the tests and profiles. _nmod_poly_mul_mid_classical evaluates each coefficient as a sum reduced after every term; _nmod_poly_mul_mid trims the operands to the window and splits a long operand into pieces of the length of the short one before calling it. Neither is used by FLINT's polynomial arithmetic, which has its own _nmod_poly_mulmid.

Precomputed operands#

When one operand is used in many products, its transform can be computed once. The second operand is then converted and transformed, multiplied pointwise and transformed back, which saves about a third of the work.

A transformed polynomial over \mathbb{Z}/n\mathbb{Z}: a plan for cyclic convolutions of length 2^d and the transform of the operand modulo x^{2^d} - 1, with its length bn and the truncation btrunc it was transformed for. If the field transposed is set (by _mul_precomp_init_tr), it holds instead the images of a polynomial v through the transposed inverse transform, for transposed products with v.

Full documentation
int _mul_precomp_init(mul_precomp_struct * M, const ulong * b, ulong bn, ulong btrunc, ulong depth, ulong len_bound, ulong direct_len, nmod_t mod, mpn_ctx_t R)

Initialises M with the transform of (b, b_n) for convolutions of length 2^d, d = depth \ge 4, in which at most len_bound products accumulate in one coefficient, and returns 1; returns 0 if more than eight primes would be needed. btrunc is the truncation of the transforms M will be used with, an upper bound for the output lengths.

Full documentation
int _nmod_poly_mul_mid_precomp(ulong * z, ulong zl, ulong zh, const ulong * a, ulong an, const mul_precomp_struct * M, nmod_t mod, mpn_ctx_t R)

Sets (z, z_h - z_l) to the coefficients [z_l, z_h) of the product of (a, a_n) with the polynomial stored in M and returns 1, or returns 0 if the window needs a transform longer than 2^d. Requires a_n \ge 1.

Full documentation
int _mul_precomp_init_tr(mul_precomp_struct * M, const ulong * v, ulong vn, ulong len_bound, ulong direct_len, nmod_t mod, mpn_ctx_t R)

Initialises M for the transposed products with (v, v_n) computed by _nmod_poly_mul_tr_precomp, in which at most len_bound products accumulate in one coefficient, and returns 1; returns 0 if no plan is available. M is freed with _mul_precomp_clear.

Full documentation
int _nmod_poly_mul_tr_precomp(ulong * z, ulong zn, const ulong * r, ulong rn, const mul_precomp_struct * M, nmod_t mod, mpn_ctx_t R)

Sets z_j = \sum_i r_i v_{i+j} \bmod n for 0 \le j < z_n, with (v, v_n) the polynomial of M made by _mul_precomp_init_tr, and returns 1; returns 0, writing nothing, if r_n + z_n - 1 > v_n. Requires r_n, z_n \ge 1, at most len_bound nonzero coefficients in r and reduced coefficients.

Full documentation

A divisor b prepared for division with remainder: the transform of the reversed power series inverse of the reversed b, and the transform of b itself for the cyclic product that gives the remainder.

Full documentation

Prepares the divisor (b, b_n) for quotients of length at most B_n, that is, for dividends of length at most b_n + B_n - 1. Requires b_n \ge 2 and an invertible leading coefficient.

Full documentation

Sets (q, a_n - b_n + 1) and (r, b_n - 1) to the quotient and remainder of (a, a_n) by the divisor prepared in M, and returns 1. Requires a_n \ge b_n. Returns 0 without computing anything if the quotient length a_n - b_n + 1 exceeds the precision B_n of the stored inverse or needs a longer transform than the one prepared.

Full documentation

Plans#

A plan fixes everything that two transformed operands must agree on to be combined pointwise: the primes, the transform length 2^d, the bound on the output coefficients, and the output window. Operands are transformed for a plan, combined pointwise any number of times, transformed back once and converted out. The guide Arithmetic in transform space explains how to use plans and operands.

A plan. The public fields are np (number of primes), depth (d), ztrunc (the transform truncation, 2^d for cyclic plans), the window zl, zh of a convolution of length zn, the coefficient bound bound_c \cdot 2^{\mathtt{bound\_e}}, and for integer plans the chunk size bits.

More
int fft_small_plan_init_nmod(fft_small_plan_t P, mpn_ctx_t R, ulong zl, ulong zh, ulong zn, ulong xtrunc_max, ulong len_bound, ulong prod_bits, nmod_t mod, ulong direct_len)

Initialises P for computing the coefficients [z_l, z_h) of convolutions of length z_n over \mathbb{Z}/n\mathbb{Z} in which at most len_bound products, each less than 2^{\mathtt{prod\_bits}}, accumulate in one coefficient. Returns 0 if more than eight primes would be needed. Requires z_l < z_h \le z_n.

More
int fft_small_plan_init_nmod_cyclic(fft_small_plan_t P, mpn_ctx_t R, ulong depth, ulong zh, ulong len_bound, ulong prod_bits, nmod_t mod)

Initialises P for cyclic convolutions modulo x^N - 1, N = 2^d with d = depth \ge 4, writing the coefficients [0, z_h), where z_h \le N. len_bound and prod_bits are as for fft_small_plan_init_nmod; a full cyclic product accumulates up to N products. Returns 0 if more than eight primes would be needed.

int fft_small_plan_init_mpn(fft_small_plan_t P, mpn_ctx_t R, ulong an_max, ulong bn_max, ulong len_bound, int is_signed)

Initialises P for products of nonnegative integers of at most an_max and bn_max limbs, of which at most len_bound are added in transform space. If is_signed is nonzero, the plan also allows subtractions and the signed exports. Returns 1 on success and 0 if no prime count and chunk size satisfy the bound.

More
int fft_small_plan_init_mpn_np(fft_small_plan_t P, mpn_ctx_t R, ulong an_max, ulong bn_max, ulong len_bound, int is_signed, ulong np)

Like fft_small_plan_init_mpn, with the regime forced for testing and profiling: np = 0 chooses automatically, np = 2 forces the two-prime geometry (and fails if its bound cannot be met), and any other value forces the profile selection with four to eight primes.

Initialises P for products of nonnegative integers of at most n_n = *nn limbs modulo B^{n_n} - 1. The length is rounded up to the nearest one for which the chunks split n_n limbs exactly into 2^d chunks, and the new value is written to *nn. Returns 0 if no geometry exists.

More
int fft_small_plan_init_mpn_window(fft_small_plan_t P, mpn_ctx_t R, ulong an_max, ulong bn_max, ulong len_bound, int is_signed, ulong lo, ulong hi)

fft_small_plan_init_mpn_window is fft_small_plan_init_mpn for products of which only the limbs [\mathit{lo}, \mathit{hi}) are needed. fft_small_plan_mpn_nslots returns the number of chunk coefficients (slots) that the inverse transform computes for operands of at most an_max and bn_max limbs, and fft_small_plan_is_cyclic whether slots alias, that is, whether the transform is shorter than the product.

More

Frees the private transform context of a plan that transforms modulo n itself, and does nothing otherwise.

Transformed operands#

An operand holds the forward transforms of one polynomial or integer modulo each prime of a plan. It is in the primal domain after a forward transform and in the product domain after a pointwise product, which carries the normalisation factor of the plan. Products can be added and subtracted in transform space, but the two domains must not be mixed, and a product cannot be multiplied again. The pointwise operations process the first P->ztrunc points, rounded up to the granularity of the plan's transforms (whole blocks of 256, or the full length 2^d below one block), which are all the points the transforms produce and read.

The two values of the domain field of an operand.

A transformed operand: np blocks of stride doubles at data, the depth and prime offset of the plan it was made for, the input truncation itrunc, the domain, and whether it owns its data.

Initialise an operand for the plan P, with storage allocated by the operand or provided by the caller, and free it. The borrowed storage must hold fft_small_op_sizeof_data(P) bytes, be aligned to 4096 bytes and outlive the operand; fft_small_op_clear does not free it.

More
void fft_small_fft_nmod(fft_small_op_t X, const ulong * a, ulong an, ulong itrunc, nmod_t mod, const fft_small_plan_t P)

Sets X to the forward transform of (a, a_n), a polynomial over \mathbb{Z}/n\mathbb{Z} with reduced coefficients, read as zero-padded to length itrunc. Requires itrunc to be a multiple of 8 and at most P->ztrunc; normally itrunc is a_n rounded up to a multiple of 256, or 2^d if the depth d is less than 8.

More

Sets X to the forward transform of the integer (a, a_n), cut into chunks of P->bits bits. Requires an integer plan and a_n \ge 1, at most the operand length the plan was made for.

More

Like fft_small_fft_mpn, with the transforms truncated to their first otrunc points, which suffices for products of at most otrunc slots. Requires otrunc \le P->ztrunc, a multiple of 256 or equal to P->ztrunc; fft_small_fft_mpn is the case otrunc = P->ztrunc.

Set Z to the pointwise product AB, respectively A^2, of operands in the primal domain. Z is then in the product domain and may alias A or B.

Add or subtract the pointwise product AB, respectively A^2, of primal operands to Z, which must be in the product domain. The sqr versions read A once and are preferable to addmul with B = A.

More

Set Z to A + B, A - B and -A, for operands in the same domain; Z gets that domain. Sums of primal operands represent sums of the inputs, whose larger coefficients the plan's bound must allow for.

Applies the inverse transform in place to an operand in the product domain, at the truncation of the plan. The normalisation was applied by the pointwise products. The primes are processed in parallel from P->ztrunc \ge 3072.

void fft_small_ifft_trunc(fft_small_op_t X, ulong itrunc, ulong clear_to, const ulong * scale, const fft_small_plan_t P)

Inverse transform of the first itrunc slots in place, with the truncation rounded up as for the plan. If scale is not NULL, scale[i] is a normalisation factor modulo the i-th prime that was not applied in the pointwise stage, and is applied after the transform. The slots [\mathtt{itrunc}, \mathtt{clear\_to}) are set to zero, for exports that read whole chunks. X is marked as being in the product domain.

The transposes of fft_small_ifft and fft_small_fft_nmod, for transposed products. fft_small_ifft_tr_nmod converts (a, a_n), read as zero-padded to P->ztrunc coefficients (so a_n \le P->ztrunc), and applies the transposed inverse transform; X is then in the primal domain. fft_small_fft_tr applies the transposed forward transform with truncation itrunc \le P->ztrunc in place to an operand in the product domain, whose first itrunc slots can then be exported.

More

Conversion out of transform space#

After fft_small_ifft, the slots hold the coefficients of the result modulo each prime. The exports reconstruct them by the Chinese remainder theorem. The mpn exports may overwrite the operand (the two-prime ones always do), which is why they take it as non-const; copy it first if it is needed afterwards.

Write the coefficients of the plan's window [z_l, z_h), respectively of the subwindow [z_l, z_h) \subseteq [P->zl, P->zh), reduced modulo n, to z, which receives z_h - z_l coefficients. The exact integer coefficients must lie in [0, P) for the product P of the plan's primes, as guaranteed by its bound for sums of products.

Writes to (z, z_n) the integer \sum_k s_k 2^{k \cdot \mathtt{bits}} reduced modulo B^{z_n}, where s_k \in [0, P) are the reconstructed slots. For a product of integers this is the product, exact if z_n is at least its length.

void fft_small_export_mpn_signed(ulong * z, ulong zn, int * sign, fft_small_op_t X, ulong nslots, const fft_small_plan_t P)
void fft_small_export_mpn_signed_trunc(ulong * z, ulong zn, int * sign, fft_small_op_t X, ulong nslots, ulong lo_limbs, const fft_small_plan_t P)

Reconstruct a signed integer from the first nslots slots, each lifted to the symmetric range (-P/2, P/2]. The absolute value is written to (z, z_n), zero-padded, and its sign to *sign. The trunc version writes the limbs from limb lo_limbs on, within (-1.5, 0.5) units of its lowest limb; with lo_limbs = 0 both are exact.

More

Write to (z, z_n) the limbs [\mathtt{lo\_limbs}, \mathtt{lo\_limbs} + z_n) of the two's complement value of the signed reconstruction, without resolving the sign; _low is the case lo_limbs = 0, which is the residue modulo B^{z_n} and exact. The value need not fit in the window.

More

Return the number of limbs that the signed reconstruction of nslots slots, respectively the unsigned one with up to len_bound accumulated products per slot, writes. An export into a shorter window must go through scratch memory, as fft_small_stage_begin arranges.

Operand pools and staged output#

Drivers that keep many transformed operands alive allocate their storage in pools, and stage conversions out through scratch memory taken from the same pool.

The alignment in bytes of transform data, 4096.

The largest amount of transform storage, in bytes, that a single transformed ring or context may plan for: its expected number of simultaneously live elements times the size of one element. Constructors decline larger requests, and their callers fall back to other algorithms (matrix multiplication then works in blocks). The default is 4 \cdot 2^{30} on 64-bit machines and 2^{30} otherwise; it may be changed. It is defined even without FLINT_HAVE_FFT_SMALL.

Flags for fft_small_op_pool_fit: take the block as a reservation in the context's scratch buffer, respectively allocate it.

A block of equal slabs for operand data plus an optional staging region, with a stack of free slabs protected by a mutex.

int fft_small_op_pool_fit(fft_small_op_pool_t pool, mpn_ctx_t R, ulong slab_size, slong count, ulong stage_bytes, int flags)

Initialise an empty pool, give it count slabs of slab_size bytes and a staging region of stage_bytes bytes, and free it. fit returns 0, leaving the pool empty, if the block can be neither reserved nor allocated as flags allow.

More
int fft_small_op_pool_owns(const fft_small_op_pool_t pool, const void * d)

Take a free slab, for fft_small_op_init_borrowed, or NULL if none is free; give a slab back; and test whether an address lies in the pool's block. Taking and giving are thread safe.

Return scratch space for limbs limbs and give it back. The space is the staging region if it is free and large enough, otherwise a free slab if use_slabs is nonzero and one is large enough, otherwise a fresh allocation; concurrent requests never share it.

ulong * fft_small_stage_begin(ulong * z, ulong zn, ulong need, fft_small_op_pool_struct * pool, int use_slabs)

Staged conversion of a value whose reconstruction writes need limbs into a window of z_n limbs. begin returns z if z_n \ge need and scratch space from the pool otherwise (pool may be NULL, meaning a plain allocation). After exporting there, and possibly adjusting the value, end copies the normalised value of length len to (z, z_n), zero pads it, releases the scratch space, and returns 0 if it does not fit (the window is then undefined).

Complex integer products#

The products behind the flint_mpn_*_complex functions of mpn_extras, which multiply Gaussian integers (a_r + i a_i)(b_r + i b_i) with parts given as magnitudes and sign bits. They are used above 230 limbs (270 for squares).

int _fft_small_mpn_mulmid_complex(nn_ptr zr, nn_ptr zi, slong lo, slong hi, nn_srcptr ar, slong arn, int ar_sgn, nn_srcptr ai, slong ain, int ai_sgn, nn_srcptr br, slong brn, int br_sgn, nn_srcptr bi, slong bin, int bi_sgn)
int _fft_small_mpn_sqrmid_complex(nn_ptr zr, nn_ptr zi, slong lo, slong hi, nn_srcptr ar, slong arn, int ar_sgn, nn_srcptr ai, slong ain, int ai_sgn)

Write the limbs [\mathit{lo}, \mathit{hi}) of the real and imaginary parts of the product, respectively the square, as two's complement windows of \mathit{hi} - \mathit{lo} limbs. Each is within one unit of \lfloor x / B^{\mathit{lo}} \rfloor for the exact part x, and exact (the residue modulo B^{\mathit{hi}}) for \mathit{lo} = 0. Return 0 if no plan exists.

More
int _fft_small_mpn_mul_complex(nn_ptr zr, slong * zr_len, nn_ptr zi, slong * zi_len, slong lo, slong hi, nn_srcptr ar, slong arn, int ar_sgn, nn_srcptr ai, slong ain, int ai_sgn, nn_srcptr br, slong brn, int br_sgn, nn_srcptr bi, slong bin, int bi_sgn)
int _fft_small_mpn_sqr_complex(nn_ptr zr, slong * zr_len, nn_ptr zi, slong * zi_len, slong lo, slong hi, nn_srcptr ar, slong arn, int ar_sgn, nn_srcptr ai, slong ain, int ai_sgn)

Write the magnitudes of the limbs [\mathit{lo}, \mathit{hi}) of the real and imaginary parts of the product, respectively the square, to zr and zi (\mathit{hi} - \mathit{lo} limbs each, enough to hold the parts shifted right by \mathit{lo} limbs), and their lengths, negated for negative parts, to *zr_len and *zi_len. Exact for \mathit{lo} = 0 and otherwise within (-1.5, 0.5) units of the lowest limb. Return 0 if no plan exists.

More

Multiplication modulo 2^N + 1#

Multiplication of residues modulo 2^N + 1 by a negacyclic convolution of their digits, computed with the small-prime transforms. This is the pointwise stage of the Schönhage–Strassen convolutions in the fft module (fft_convolution_sd_fft), which fmpz_poly and fmpzi multiplication use for large coefficients.

Residues occupy n + 1 limbs, n = N/\mathtt{FLINT\_BITS}. An input may have top limb 0 or 1 with arbitrary other limbs and is read modulo 2^N + 1. The output is fully reduced: the unique representative in [0, 2^N], with top limb 1 only for 2^N.

A context for one ring \mathbb{Z}/(2^N + 1)\mathbb{Z}, holding N, the digit size b, the digit count m = N/b, the number of primes and the twisting tables, and a scratch object with the mutable state of one multiplication.

Full documentation

Initialises C for multiplication modulo 2^N + 1 with m digits of b = N/m bits, taking the primes from R, normally get_default_mpn_ctx(), and frees it. N must be a positive multiple of FLINT_BITS, and m a power of two at least 16 dividing N, or 0 to let the function choose. Throws if N is not a positive multiple of FLINT_BITS or no configuration exists.

Full documentation

Initialise and free the scratch object for multiplications with C. The context is read-only during multiplication, so several threads can share it, each with its own scratch object.

Full documentation

Sets z = xy \bmod 2^N + 1. z may alias x or y; if x == y a square is computed with one forward transform.

Full documentation

Multiplication by a fixed operand. transform stores the transform of y in F, an array of transformed_size(C) doubles; mul_cached then sets z = xy \bmod 2^N + 1, like sd_fft_mpn_mulmod_2expp1 with one forward transform less.

Full documentation

Returns the number of primes the context uses for digits of b bits and m = 2^{\mathtt{depth}} digits, as described for the context, or -1 if there is none.

Full documentation

Transforms modulo one prime#

The number-theoretic transforms themselves. Data is an array of doubles holding integers, transformed in place; the algorithm and the bounds are described in FFTs modulo word-size primes in floating point. These functions are internal, but stable enough to be used directly; see Transforms modulo one prime.

The block size 256 = 2^8 in doubles. Transforms longer than one block work on whole blocks in their outer layers, and truncations are rounded up to whole blocks.

The transform context of one prime p: p and pinv = 1/p as doubles, mod for integer arithmetic modulo p, a primitive root of unity primitive_2power_root of order 2^v with 2^v \| p - 1, and the twiddle tables w2tab filled to w2tab_depth, guarded by a mutex.

More

The number of twiddle tables filled at initialisation (12, for transforms up to length 2^{12}) and the maximal number of tables (40).

Initialise the context of the prime p = pp and free it. Throws if p fails fft_small_mulmod_satisfies_bounds, if p - 1 is odd or if 2^4 \nmid p - 1. Primality is assumed, not checked.

Make sure that the twiddle tables cover transforms of length 2^{\mathtt{depth}}, filling the missing tables under the context's mutex. Throw if 2^{\mathtt{depth}} \nmid p - 1. sd_fft_trunc and sd_ifft_trunc call this themselves.

void sd_fft_trunc(sd_fft_ctx_t Q, double * d, ulong L, ulong itrunc, ulong otrunc)

Truncated forward transform of length 2^L in place: with f the polynomial with coefficients d[0], ..., d[itrunc - 1], sets d[sd_fft_ctx_trunc_index(L, i)] to a value congruent to f(w_i) for 0 \le i < \mathtt{otrunc}. The inputs must lie in (-3p, 3p), and so do the outputs.

Full documentation
void sd_ifft_trunc(sd_fft_ctx_t Q, double * d, ulong L, ulong trunc)

Truncated inverse transform of length 2^L in place: if d[i] holds the value at position i of the forward transform of a polynomial g of length at most trunc, for i < \mathtt{trunc}, sets d[i] to a value congruent to 2^L g_i for i < \mathtt{trunc}. The inputs must lie in (-2p, 2p); the outputs lie in (-3p, 3p).

Full documentation
void sd_fft_trunc_tr(sd_fft_ctx_t Q, double * d, ulong L, ulong itrunc, ulong otrunc)
void sd_ifft_trunc_tr(sd_fft_ctx_t Q, double * d, ulong L, ulong trunc)

The transposes of sd_fft_trunc and sd_ifft_trunc with the same parameters, in place: for all vectors a and v, \langle \mathtt{sd\_fft\_trunc}(a), v \rangle = \langle a, \mathtt{sd\_fft\_trunc\_tr}(v) \rangle, and likewise for the inverse transform. sd_fft_trunc_tr reads the first otrunc entries, indexed like the output of sd_fft_trunc, and sets d_t to a value congruent to \sum_{i < \mathtt{otrunc}} d[\mathtt{sd\_fft\_ctx\_trunc\_index}(L, i)]\, w_i^t for 0 \le t < \mathtt{itrunc}. Each costs the same as the transform it transposes.

Full documentation
void sd_fft_ctx_point_mul(const sd_fft_ctx_t Q, double * a, const double * b, ulong m_, ulong depth)
void sd_fft_ctx_point_sqr(const sd_fft_ctx_t Q, double * a, ulong m_, ulong depth)

Set a_i \gets m a_i b_i, respectively m a_i^2, modulo p for i < 2^{\mathtt{depth}}, with 0 \le m \le p and depth at least 4. Inputs in (-3p, 3p) give outputs in (-3p/2, 3p/2), valid inputs for sd_ifft_trunc.

Full documentation
double sd_fft_ctx_w(const sd_fft_ctx_t Q, ulong j)
double sd_fft_ctx_w2(const sd_fft_ctx_t Q, ulong j)

Return the root of unity w_j, w_{2j}, and -w_{2j}^{-1} modulo p, as integers in [-p/2, p/2]. Here w_0 = 1 and, for 2^{k-1} \le j < 2^k, w_j = \omega^{r} where \omega is a primitive 2^k-th root of unity and r is j with its k bits reversed; the roots for different k are chosen compatibly, \omega_{2^k} = \omega_{2^{k+1}}^2. The tables must cover the index.

More

The position of f(w_i) in the output of a forward transform of length 2^L: i itself for L < 4, and otherwise i with the two 2-bit fields of its low four bits exchanged, which transposes each group of 16 values as a 4 \times 4 matrix.

double * sd_fft_ctx_blk_index(double * d, ulong I)

The offset 256 I of block I, the address d + 256 I, and the number 2^L of doubles of a transform of length 2^L.

SET_J_BITS_AND_J_R(j_bits, j_r, j)
SET_J_BITS_AND_J_MR(j_bits, j_mr, j)

Split a twiddle index j into the table number j_bits (the bit length of j) and the index in that table: j_r = j - 2^{\mathtt{j\_bits} - 1} for w_{2j}, and j_mr = 2^{\mathtt{j\_bits}} - 1 - j, which locates -w_{2j}^{-1}. Both are 0 for j = 0.

Returns whether the floating-point modular multiplication modulo n maps products in (-2n^2, 2n^2) into (-n, n) and products in (-4n^2, 4n^2) into (-3n/2, 3n/2), by a bound that uses the actual error of the double 1/n. Every prime below 2^{49} passes, and about one 50-bit prime in 900 fails.

AlgorithmModular arithmetic in floating pointExact arithmetic modulo n < 2^{50} on integers stored in doubles, using a precomputed 1/n and a fused multiply-add to split the product, as in FLINT's small-prime FFT.

Returns whether a transform of length 2^{\mathtt{depth}} can be computed modulo n itself: 2 < n \le 2^{50}, n passes fft_small_mulmod_satisfies_bounds, depth is at most 40 and 2^{\max(\mathtt{depth}, 4)} \mid n - 1 (the context initialisation sd_fft_ctx_init_prime needs 2^4 \mid n - 1 for every depth). Primality is assumed.

Chinese remaindering and integer conversion#

Data and helpers behind the conversions of the multiplication drivers. They are internal.

Chinese remaindering data for the first nprimes primes p_0, \ldots, p_{k-1} of a context, with product P: the cofactors P / p_i and P, each of coeff_len limbs (enough to hold kP), and the reduced cofactors (P / p_i) \bmod p_i. prime is p_{k-1}.

void crt_data_init(crt_data_t C, ulong prime, ulong coeff_len, ulong nprimes)

Allocate storage for the data, which the caller fills in, and free it.

Pointers to the cofactor P / p_i (coeff_len limbs; the second form takes coeff_len as n for the compiler), to P (coeff_len limbs), and to the single limb (P / p_i) \bmod p_i.

The number of primes of a context (8), the capacity of its profile table (20), the lane count of the vectors used in the conversions (4), and the length of the tables of powers of two (256), which must grow with the number of primes.

profile_entry_struct
profile_entry_t

A packing profile: the number of primes np, the chunk size bits, the largest second operand length bn_bound for which \lceil 64 b_n / \mathtt{bits} \rceil 2^{2 \mathtt{bits}} \le P, and the vectorised conversion to_ffts of type to_ffts_func, which reduces the chunks of an integer modulo all primes at once.

More

The type of the windowed Chinese remainder reconstructions of the integer drivers, which turn residues of chunk coefficients into limbs.

Return the vectorised conversion of integers into chunks of bits bits modulo np primes, or NULL if none is instantiated, and the reconstruction for 3 \le np \le 8 primes. Used by the negacyclic engine.

void _convert_block(ulong * Xs, sd_fft_ctx_struct * Rffts, double * d, ulong dstride, ulong np, ulong Iv)
void _convert_block_1_mod(ulong * Xs, sd_fft_ctx_struct * Rffts, double * d, ulong dstride, ulong I, double p2, double p2inv)

For each prime l < np, reduce block I of the data d + l \cdot dstride to [0, p_l) and store it as integers at Xs + 256 l. The second form converts only the first prime and reduces the results further modulo the double p2 (with p2inv = 1/p_2).

Plan internals#

The steps of plan construction, used by drivers in other modules that build their own plans.

Chooses the least number of primes k \le np_max whose product is at least c 2^e, starting at the first prime of P->R, and records the bound. Returns 0 if there is none.

void _fft_small_plan_set_window(fft_small_plan_t P, ulong zl, ulong zh, ulong zn, ulong xtrunc_max, ulong min_depth)

Choose the depth and truncation for the window [z_l, z_h) of a convolution of length z_n with operands of truncated length at most xtrunc_max, and record the window. Require z_l < z_h \le z_n.

More
int _fft_small_plan_fit_window(fft_small_plan_t P, ulong zl, ulong zh, ulong zn, ulong xtrunc_max, ulong min_depth)

Like _fft_small_plan_set_window with the depth of P fixed. Returns 0 if the depth is below min_depth or the window needs a longer transform.

More

The truncation of an operand or output of length x: x rounded up to a multiple of 256 or, below one block, the full transform length. _fft_small_len_trunc anticipates it before a plan exists, using the length 2^{\max(4, \lceil \log_2 x \rceil)} below 256; _fft_small_op_trunc gives the one the plan P imposes, 2^d for a depth d < 8.

Computes the stride and the normalisation factors m[i] from the primes and the depth, which must be set.

Convolution engine#

The engine shared by the polynomial drivers of this and other modules. Stage 1 converts and transforms the operands for each prime, multiplies pointwise with the normalisation folded in, and transforms back; it runs in parallel over the primes. Stage 2 reconstructs ranges of output coefficients by the Chinese remainder theorem, in parallel over the ranges. The coefficient type enters through callbacks.

The callbacks: conversion of an operand into the double buffer of one prime; reconstruction of the output coefficients [\mathit{start}, \mathit{stop}) (relative to z_l) from the residues; and an optional serial pass after stage 2 that receives the range boundaries and the per-range values that the reconstruction left in its local slots.

The number of words (4) of per-range output, such as carries, a reconstruction callback can leave for the finishing pass.

One stage 2 range: its end stop_zi and its local words.

Three threshold predicates for a coefficient type: the number of threads for stage 1, whether each stage 1 worker should transform the second operand on an extra thread, and whether to request up to eight threads for stage 2 (may be NULL).

The arguments of one convolution: both operands with their lengths, auxiliary values and truncations (or a precomputed transform bfft of the second operand with its stride), the squaring flag, the transposed flag, the size used by the tuning predicates, the bound min_an_bn on the products per output coefficient, the callbacks with their params, and the tuning table.

More

Computes the window of the plan of the convolution described by A into z, using the scratch buffer of the plan's context.

Two-prime pipeline#

The integer multiplication used up to 40000 limbs. The chunks are below both primes, so conversion is plain bit slicing, and reconstruction is one Garner step [Gar1959] with the normalisation folded into its constants. See The two-prime pipeline.

The largest operand length, 40000 limbs, for which mpn_ctx_mpn_mul and fft_small_plan_init_mpn prefer the two-prime pipeline.

The full product, its low z_h limbs, and its limbs [z_l, z_h), by the two-prime pipeline. Require a_n \ge b_n \ge 1 and z_l < z_h \le a_n + b_n. The window is exact for z_l = 0 and otherwise smaller than the exact window by 0 or 1 units of its lowest limb.

More
int _fft_small_np2_choose(const mpn_ctx_struct * R, ulong an, ulong bn, ulong len_bound, ulong * bits, ulong * depth)

Chooses the least depth d \in [8, 30] and then the largest chunk size b \in [40, 45] with \lceil 64 a_n / b \rceil + \lceil 64 b_n / b \rceil - 1 \le 2^d and len_bound \cdot \lceil 64 b_n / b \rceil \cdot 2^{2b} < p_0 p_1. Returns 0 if there is none.

void _fft_small_np2_pack(double * d, double * d2, nn_srcptr x, ulong xn, ulong len, ulong itrunc, ulong bits)

Writes the first len chunks of bits \le 45 bits of (x, x_n) as doubles to both d and d2, followed by zeros up to itrunc.

void _fft_small_np2_crt_recompose(const mpn_ctx_struct * R, nn_ptr z, ulong zl, ulong zh, double * d0, double * d1, ulong nchunks, ulong navail8, ulong bits, ulong depth)

Writes to z the limbs [z_l, z_h) of \sum_j v_j 2^{j \cdot \mathtt{bits}} over nchunks chunk values v_j given by their residues modulo p_0 in d0 and modulo p_1 in d1, which it overwrites. Unless depth is UWORD_MAX, the residues are raw inverse transform outputs and are multiplied by 2^{-\mathtt{depth}}. navail8 is the number of entries available to the vectorised Garner step.

Word and limb helpers#

Small inline helpers defined in this header.

ulong n_pow2(int k)

Return 2^k, and the minimum and maximum of two unsigned and of two signed words.

Return \lceil a/b \rceil, b \lceil a/b \rceil and b \lfloor a/b \rfloor. The first two compute a + b - 1 and are wrong if it overflows.

The bit length of x (0 for x = 0; _nz requires x \ne 0), the numbers of leading and trailing zero bits (FLINT_BITS for x = 0), and 2^{k} - 1 for a of bit length k.

Return \lceil \log_2 x \rceil and \lfloor \log_2 x \rfloor for x \ge 1; both are 0 for x = 0.

int flint_mpn_cmp_ui_2exp(const ulong * a, ulong an, ulong b, ulong e)

The bit length of (a, a_n), which need not be normalised, and the sign of a - b 2^e.

unsigned char flint_mpn_add_inplace_c(ulong * z, ulong zn, ulong * a, ulong an, unsigned char cf)

Adds (a, a_n) and the carry cf to (z, z_n) in place, propagating the carry through at most z_n limbs, and returns the carry out. Requires z_n \ge a_n \ge 1.

References#

Cite this page

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