FLINT3.7.0-dev
Module · 398 functions

nmod_poly.h

#include <flint/nmod_poly.h>

This module implements dense univariate polynomials over Z/nZ\mathbb{Z}/n\mathbb{Z} for a word-size modulus n≥1n \ge 1. A polynomial is an nmod_poly_t: an array of ulong coefficients reduced modulo nn, together with its length and an nmod_t for the modulus. Multiplication switches between the classical algorithm, several variants of Kronecker substitution and FFTs modulo word-size primes (FFTs modulo word-size primes in floating point), so that a product of length mm costs O(mlog⁡m)O(m \log m) word operations for large mm. Division, power series inversion, GCDs, multipoint evaluation, interpolation and composition are reduced to multiplication by Newton iteration, the half-GCD algorithm and subproduct trees, and inherit its quasi-linear complexity. Factorisation and irreducibility testing are in nmod_poly_factor.h, and polynomial matrices in nmod_poly_mat.h.

The guides below explain how to use the module; start with Getting started with nmod_poly.

OverviewMultiplying polynomials over Z/nZHow nmod_poly multiplies: classical products built on modular dot products, Kronecker substitution (KS, KS2, KS4), and the small-prime FFT of fft_small, with the length and modulus-size cutoffs that choose between them for full, low, middle and high products.

Guides#

Types and conventions#

A polynomial over Z/nZ\mathbb{Z}/n\mathbb{Z}. The structure has the fields coeffs (an array of alloc coefficients), alloc, length and mod (an nmod_t for nn, see nmod.h). An nmod_poly_t is an array of one nmod_poly_struct, so it is passed by reference. The coefficient of xix^i is coeffs[i].

  • The modulus is stored in each polynomial. All polynomials passed to one function must have the same modulus, which is not checked.
  • A polynomial is normalised if its length is zero or its leading coefficient coeffs[length - 1] is nonzero. The zero polynomial has length 0 and degree −1-1. Coefficients are reduced, that is, lie in [0,n)[0, n). All functions require normalised inputs with reduced coefficients and produce such outputs. This is not checked.
  • Functions without a leading underscore manage memory and allow every output to be the same object as any input, unless stated otherwise. Several outputs of one function (such as quotient and remainder) must be distinct objects.
  • Functions with a leading underscore work on plain coefficient arrays (poly, len), take the modulus as an nmod_t, and leave memory management to the caller. They usually require nonzero lengths, place ordering conditions on them, write a fixed number of coefficients (including leading zeros), and do not allow the output to overlap the inputs. Each function states its conditions.
  • Many functions need to invert leading coefficients, or integers up to the length, and therefore assume that nn is prime: division by a polynomial whose leading coefficient is not a unit, GCDs, resultants, modular inverses, square roots, interpolation and the transcendental power series. This is not checked. A non-invertible element usually causes an exception (FLINT_IMPINV or FLINT_ERROR), but a composite modulus can also give wrong results without warning. The GCD and resultant functions always throw FLINT_IMPINV when they meet a leading coefficient that is not invertible.

The conventions for arithmetic modulo a fixed polynomial are explained in Computing modulo a fixed polynomial.

Memory management#

Initialise poly as the zero polynomial modulo n≥1n \ge 1, without allocating coefficients. nmod_poly_init_preinv takes the precomputed inverse ninv = n_preinvert_limb(n) instead of computing it.

void nmod_poly_init_mod(nmod_poly_t poly, const nmod_t mod)

Initialises poly as the zero polynomial with the modulus mod, which must have been set up with nmod_init. This is the cheapest way to create polynomials with the modulus of an existing one, nmod_poly_init_mod(a, b->mod).

void nmod_poly_init2(nmod_poly_t poly, ulong n, slong alloc)

Like nmod_poly_init and nmod_poly_init_preinv, but allocate space for alloc coefficients.

Changes the allocated space of poly to alloc coefficients. If the length exceeds alloc, the polynomial is truncated to length alloc and normalised. For alloc = 0 the coefficients are freed and poly becomes zero.

Ensures that poly has space for at least alloc coefficients. If it has to grow, it grows to at least twice the old allocation, so that repeated calls with increasing lengths cost amortised linear time. The length and the coefficients are not changed.

Frees the memory used by poly, which must be initialised again before it is used.

void nmod_poly_set_mod(nmod_poly_t poly, const nmod_t mod)

Replaces the modulus of poly by mod without changing the coefficients, which must be reduced modulo the new modulus.

Sets the length field of poly to len without zeroing or normalising anything. poly must have space for len coefficients.

Decreases the length of poly until the leading coefficient is nonzero or the length is zero. This is the usual last step after writing coefficients with an underscore function.

Length, degree and basic properties#

Return the length and the degree of poly. The zero polynomial has length 0 and degree −1-1.

Returns the modulus nn of poly.

Returns the number of bits of the largest coefficient of poly, or 0 for the zero polynomial.

Returns a pointer to the leading coefficient of poly, or NULL if poly is zero.

Return the number of nonzero coefficients.

Returns whether poly is the zero polynomial.

Return whether poly is the constant 1, respectively the generator xx. For n=1n = 1 both return 1, since every polynomial is zero modulo 1.

Returns whether poly is a nonzero constant, which for prime nn is the same as being a unit. For composite nn the result does not tell whether the constant is invertible. For n=1n = 1 it returns 1.

Returns whether poly is nonzero with leading coefficient 1.

Assignment and coefficients#

Sets a to a copy of b.

Swaps poly1 and poly2 in constant time by swapping the structures, including the moduli.

Set res to 0 and to 1. Modulo n=1n = 1, nmod_poly_one sets res to the zero polynomial.

Set res to poly truncated to length len, that is, poly modulo xlenx^{\mathit{len}}, and truncate poly in place. The result is normalised. Nothing happens if len is at least the length.

void _nmod_poly_reverse(nn_ptr output, nn_srcptr input, slong len, slong m)
void nmod_poly_reverse(nmod_poly_t output, const nmod_poly_t input, slong m)

Set output to the reversal xm−1f(1/x)x^{m-1} f(1/x) of the input ff viewed as a polynomial of length m≥0m \ge 0: coefficient ii of the output is coefficient m−1−im - 1 - i of the input, taken as 0 beyond its length. Input coefficients from index mm on are ignored.

More

Returns the coefficient of xjx^j, or 0 if jj is at least the length. Requires j≥0j \ge 0.

Sets the coefficient of xjx^j to c mod nc \bmod n, for any cc. The polynomial grows, with zero coefficients in between, or shrinks if the leading coefficient is set to zero.

Comparison#

Returns whether a and b are equal. The moduli are not compared.

int nmod_poly_equal_ui(const nmod_poly_t poly, ulong cst)

Return whether poly is the constant cst. nmod_poly_equal_nmod requires cst to be reduced; nmod_poly_equal_ui reduces it first.

int nmod_poly_equal_trunc(const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)

Returns whether poly1 and poly2 agree modulo xnx^n. A negative nn is treated as 0.

Random polynomials#

The rand functions draw coefficients uniformly from [0,n)[0, n). The randtest functions use n_randtest, which favours special values and sparse polynomials; they are meant for test code. Functions that produce irreducible or primitive polynomials repeat until nmod_poly_is_irreducible (from nmod_poly_factor.h) succeeds and require a prime modulus.

Set poly to a random polynomial of length at most len, respectively a random monic polynomial of length exactly len≥1\mathit{len} \ge 1.

Sets poly to a random irreducible polynomial of length at most len. Since nmod_poly_is_irreducible regards nonzero constants as irreducible, the result can be a constant, and it need not be monic.

Set poly to a random test polynomial of length at most len, a nonzero one (requires len≥1\mathit{len} \ge 1 and n≥2n \ge 2), and a monic one of length exactly len≥1\mathit{len} \ge 1.

Set poly to a random irreducible polynomial of length at most len (which may be a constant), and to a random monic irreducible polynomial of length exactly len≥2\mathit{len} \ge 2.

Sets poly to a random monic irreducible polynomial of length len≥2\mathit{len} \ge 2 whose root generates the multiplicative group of the field Fn[x]/(poly)\mathbb{F}_n[x]/(\mathit{poly}). Primitivity is tested with fq_nmod_is_primitive.

Set poly to a random monic polynomial of length len with at most three nonzero terms xlen−1+axk+bx^{\mathit{len}-1} + a x^k + b, 0<k<len−10 < k < \mathit{len} - 1 (requires len≥3\mathit{len} \ge 3), respectively at most five nonzero terms xlen−1+a3x3+a2x2+a1x+a0x^{\mathit{len}-1} + a_3 x^3 + a_2 x^2 + a_1 x + a_0 (requires len≥5\mathit{len} \ge 5).

Try up to max_attempts random trinomials, respectively pentomials, as above and return 1 as soon as one is irreducible, or 0 if none is. For max_attempts = 0 they try until they succeed, which does not terminate if there is no irreducible polynomial of that shape.

Sets poly to a sparse monic irreducible polynomial of length len: it tries 2len2 \mathit{len} trinomials, then 2len2 \mathit{len} pentomials, then random polynomials with a growing number of terms.

Input and output#

The plain format is the length, the modulus and the coefficients from the constant term upwards, for example "3 7 6 0 5" for 5x2+65x^2 + 6 modulo 7 (two spaces before the first coefficient). The pretty format writes the terms from the highest degree down, for example "5*x^2+6".

char * nmod_poly_get_str(const nmod_poly_t poly)
char * nmod_poly_get_str_pretty(const nmod_poly_t poly, const char * x)

Return poly as a string in the plain format and in the pretty format with variable name x. The zero polynomial is "0 n" and "0". Free the string with flint_free.

int nmod_poly_set_str(nmod_poly_t poly, const char * s)

Reads poly from a string in the plain format and returns 1, or returns 0 if the string is not in this format. The modulus in the string is ignored and the coefficients are not reduced: they must be smaller than the modulus of poly.

int nmod_poly_fprint(FILE * f, const nmod_poly_t poly)
int nmod_poly_print_pretty(const nmod_poly_t a, const char * x)
int nmod_poly_fprint_pretty(FILE * f, const nmod_poly_t a, const char * x)

Write the polynomial to stdout or to f, in the plain or the pretty format. Return a positive value on success and a non-positive value on failure.

int nmod_poly_fread(FILE * f, nmod_poly_t poly)

Read a polynomial in the plain format from stdin or from f. Unlike nmod_poly_set_str, they reinitialise poly with the modulus that was read. Return 1 on success and 0 if the input is not in the plain format. The coefficients are not reduced.

Shifting#

Set res to poly times xkx^k, for k≥0k \ge 0. The underscore version writes len+k\mathit{len} + k coefficients and allows res == poly.

Set res to poly divided by xkx^k, discarding the remainder, for k≥0k \ge 0. In the underscore version len is the length of the output: it sets res[i] = poly[i + k] for 0≤i<len0 \le i < \mathit{len}, so poly must have at least len+k\mathit{len} + k coefficients. It allows res == poly.

Addition and subtraction#

void _nmod_poly_add(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)
void _nmod_poly_sub(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)

Set res to the sum and the difference of (poly1, len1) and (poly2, len2), writing max⁡(len1,len2)\max(\mathit{len1}, \mathit{len2}) coefficients, which may include leading zeros. Any lengths, including 0, are allowed, and res may be poly1 or poly2.

void nmod_poly_add(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)
void nmod_poly_sub(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)
void nmod_poly_neg(nmod_poly_t res, const nmod_poly_t poly1)

Set res to poly1+poly2\mathit{poly1} + \mathit{poly2}, poly1−poly2\mathit{poly1} - \mathit{poly2} and −poly1-\mathit{poly1}.

void nmod_poly_add_series(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)
void nmod_poly_sub_series(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)

Set res to the sum and the difference modulo xnx^n. A negative nn is treated as 0.

Set res to poly+c\mathit{poly} + c and poly−c\mathit{poly} - c, for any cc.

Scalar multiplication#

Sets res to c⋅polyc \cdot \mathit{poly}, for reduced cc. The result is normalised, which matters for composite nn.

Sets res to res+c⋅poly\mathit{res} + c \cdot \mathit{poly}, for reduced cc.

void _nmod_poly_make_monic(nn_ptr output, nn_srcptr input, slong len, nmod_t mod)
void nmod_poly_make_monic(nmod_poly_t output, const nmod_poly_t input)

Set output to input divided by its leading coefficient, which must be invertible modulo nn (otherwise FLINT_IMPINV is thrown). nmod_poly_make_monic throws FLINT_DIVZERO for the zero polynomial; the underscore version requires len≥1\mathit{len} \ge 1 and allows output == input.

Multiplication#

nmod_poly_mul and the other functions without an algorithm in their name choose the algorithm from the lengths and the number of bits of nn:

  • the classical algorithm, computing each coefficient as a dot product with _nmod_vec_dot_rev (see Computing dot products), for short operands;
  • Kronecker substitution (KS), which packs the coefficients into integers and multiplies those with flint_mpn_mul, and its multipoint variants KS2 and KS4 [Har2009a], for medium lengths;
  • the small-prime FFT of fft_small for long operands, when FLINT is built with it (the usual case on x86-64 and ARM64). Moduli n≤23n \le 23 use a repacked product of half the length.

The crossover points, tabulated for each bit size of nn, are explained in Multiplying polynomials. Truncated products (mullow), high products (mulhigh) and middle products (mulmid) compute part of the product for about the cost of the part; middle products are the transposes of ordinary products and are what Newton iteration needs (Middle products and the transposition principle).

OverviewMultiplying polynomials over Z/nZHow nmod_poly multiplies: classical products built on modular dot products, Kronecker substitution (KS, KS2, KS4), and the small-prime FFT of fft_small, with the length and modulus-size cutoffs that choose between them for full, low, middle and high products.

Choosing the algorithm automatically#

void _nmod_poly_mul(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)
void nmod_poly_mul(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)

Set res to the product poly1⋅poly2\mathit{poly1} \cdot \mathit{poly2}. The underscore version requires len1≥len2≥1\mathit{len1} \ge \mathit{len2} \ge 1, writes len1+len2−1\mathit{len1} + \mathit{len2} - 1 coefficients and does not allow res to overlap the inputs; poly1 == poly2 (squaring) is allowed and faster.

Full documentation
void _nmod_poly_mullow(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong trunc, nmod_t mod)
void nmod_poly_mullow(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong trunc)

Set res to the product truncated to length trunc, that is, poly1⋅poly2 mod xtrunc\mathit{poly1} \cdot \mathit{poly2} \bmod x^{\mathit{trunc}}. The underscore version requires len1≥len2≥1\mathit{len1} \ge \mathit{len2} \ge 1 and 1≤trunc≤len1+len2−11 \le \mathit{trunc} \le \mathit{len1} + \mathit{len2} - 1, writes trunc coefficients and does not allow aliasing. Inputs longer than trunc are allowed.

Full documentation
void _nmod_poly_mulhigh(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong n, nmod_t mod)
void nmod_poly_mulhigh(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)

Set the coefficients of res from index nn on to those of the product. The coefficients below nn are either zero or the coefficients of the product. The underscore version requires len1≥len2≥1\mathit{len1} \ge \mathit{len2} \ge 1, writes len1+len2−1\mathit{len1} + \mathit{len2} - 1 coefficients and does not allow aliasing.

Full documentation
void _nmod_poly_mulmid(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, nmod_t mod)
void nmod_poly_mulmid(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong nlo, slong nhi)

Set res to the coefficients nlo,…,nhi−1\mathit{nlo}, \ldots, \mathit{nhi} - 1 of the product, that is, ⌊poly1⋅poly2/xnlo⌋ mod xnhi−nlo\lfloor \mathit{poly1} \cdot \mathit{poly2} / x^{\mathit{nlo}} \rfloor \bmod x^{\mathit{nhi} - \mathit{nlo}}. The underscore version requires len1,len2≥1\mathit{len1}, \mathit{len2} \ge 1 in either order and 0≤nlo<nhi≤len1+len2−10 \le \mathit{nlo} < \mathit{nhi} \le \mathit{len1} + \mathit{len2} - 1, writes nhi−nlo\mathit{nhi} - \mathit{nlo} coefficients and does not allow aliasing. The non-underscore version accepts any 0≤nlo≤nhi0 \le \mathit{nlo} \le \mathit{nhi}.

Full documentation

Classical multiplication#

void _nmod_poly_mul_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)
void nmod_poly_mul_classical(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)

Set res to the product by the classical algorithm, with O(len1⋅len2)O(\mathit{len1} \cdot \mathit{len2}) operations. The underscore version requires len1≥len2≥1\mathit{len1} \ge \mathit{len2} \ge 1 and does not allow aliasing.

More
void _nmod_poly_mullow_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong trunc, nmod_t mod)
void nmod_poly_mullow_classical(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong trunc)

Set res to the product modulo xtruncx^{\mathit{trunc}} by the classical algorithm. The underscore version requires len1≥len2≥1\mathit{len1} \ge \mathit{len2} \ge 1 and 1≤trunc≤len1+len2−11 \le \mathit{trunc} \le \mathit{len1} + \mathit{len2} - 1, and does not allow aliasing.

void _nmod_poly_mulhigh_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong start, nmod_t mod)
void nmod_poly_mulhigh_classical(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong start)

Set the coefficients of res from index start on to those of the product, by the classical algorithm, and the coefficients below start to zero. The underscore version requires len1≥len2≥1\mathit{len1} \ge \mathit{len2} \ge 1, writes len1+len2−1\mathit{len1} + \mathit{len2} - 1 coefficients and does not allow aliasing.

void _nmod_poly_mulmid_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, nmod_t mod)
void nmod_poly_mulmid_classical(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong nlo, slong nhi)

Set res to the coefficients nlo,…,nhi−1\mathit{nlo}, \ldots, \mathit{nhi} - 1 of the product by the classical algorithm, with the same conventions as _nmod_poly_mulmid and nmod_poly_mulmid.

Kronecker substitution#

Kronecker substitution evaluates both polynomials at a power of two 2b2^b, with bb large enough that the coefficients of the product do not overlap, multiplies the resulting integers and reads off the coefficients. KS2 evaluates at 2b2^b and −2b-2^b and KS4 also at 2−b2^{-b} and −2−b-2^{-b}, which halves, respectively quarters, the size of each integer product [Har2009a]. All three variants read their inputs completely before writing the output, so the output may be the same array as an input.

AlgorithmKronecker substitutionMultiplies polynomials over Z/nZ\mathbb{Z}/n\mathbb{Z} by packing their coefficients into large integers, multiplying the integers and unpacking; Harvey's KS2 and KS4 variants evaluate at ±2^b and ±2^(-b) to split the integer product into two or four smaller ones.
void _nmod_poly_mul_KS(nn_ptr out, nn_srcptr in1, slong len1, nn_srcptr in2, slong len2, nmod_t mod)
void nmod_poly_mul_KS(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)

Set res to the product by Kronecker substitution. The underscore version requires len1,len2≥1\mathit{len1}, \mathit{len2} \ge 1 in either order.

More
void _nmod_poly_mullow_KS(nn_ptr out, nn_srcptr in1, slong len1, nn_srcptr in2, slong len2, slong n, nmod_t mod)
void nmod_poly_mullow_KS(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)

Set res to the product modulo xnx^n by Kronecker substitution. The underscore version requires len1,len2≥1\mathit{len1}, \mathit{len2} \ge 1 and 1≤n≤len1+len2−11 \le n \le \mathit{len1} + \mathit{len2} - 1. It multiplies the operands truncated to length nn in full and unpacks the low nn coefficients.

void _nmod_poly_mulmid_KS(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, nmod_t mod)
void nmod_poly_mulmid_KS(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong nlo, slong nhi)

Set res to the coefficients nlo,…,nhi−1\mathit{nlo}, \ldots, \mathit{nhi} - 1 of the product by Kronecker substitution, with the same conventions as _nmod_poly_mulmid and nmod_poly_mulmid, except that the output may alias the inputs.

void _nmod_poly_mul_KS2(nn_ptr res, nn_srcptr op1, slong n1, nn_srcptr op2, slong n2, nmod_t mod)
void nmod_poly_mul_KS2(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)

Set res to the product by Kronecker substitution at 2b2^b and −2b-2^b [Har2009a]. The underscore version requires n1≥n2≥1\mathit{n1} \ge \mathit{n2} \ge 1.

More
void _nmod_poly_mul_KS4(nn_ptr res, nn_srcptr op1, slong n1, nn_srcptr op2, slong n2, nmod_t mod)
void nmod_poly_mul_KS4(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)

Set res to the product by Kronecker substitution at ±2b\pm 2^b and at the reciprocal points ±2−b\pm 2^{-b} [Har2009a]. The underscore version requires n1≥n2≥1\mathit{n1} \ge \mathit{n2} \ge 1.

More

FFT multiplication#

These functions call the small-prime FFT of fft_small (fft_small.h), which multiplies modulo one to several 50-bit primes and reconstructs the coefficients modulo nn by the Chinese remainder theorem (Multiplication with several primes and CRT). They exist only when FLINT is built with fft_small (FLINT_HAVE_FFT_SMALL); otherwise _nmod_poly_mulmid_fft_small and _nmod_poly_mullow_fft_small throw an exception and the want functions return 0.

Write the coefficients znlo,…,zn−1\mathit{znlo}, \ldots, \mathit{zn} - 1 (respectively 0,…,zn−10, \ldots, \mathit{zn} - 1) of the product of (a, an) and (b, bn) to z, using fft_small. Require an,bn≥1\mathit{an}, \mathit{bn} \ge 1, in either order, and 0≤znlo<zn≤an+bn−10 \le \mathit{znlo} < \mathit{zn} \le \mathit{an} + \mathit{bn} - 1; the output must not overlap the inputs.

More
int _nmod_poly_mullow_want_fft_small(slong len1, slong len2, slong n, int squaring, nmod_t mod)

Return whether fft_small is expected to be the fastest algorithm for a product of lengths len1 and len2 truncated to length nn (a full product if n=len1+len2−1n = \mathit{len1} + \mathit{len2} - 1), respectively for mm coefficients of a middle product whose shorter operand, after trimming, has length len2.

More

Internal helper of _nmod_poly_mulmid_fft_small for n≤23n \le 23: if the coefficients are small enough, writes the coefficients znlo,…,zn−1\mathit{znlo}, \ldots, \mathit{zn} - 1 of the product to z and returns 1; otherwise returns 0 without writing anything. The conditions on the arguments are those of _nmod_poly_mulmid_fft_small.

More

Powering#

void _nmod_poly_pow(nn_ptr res, nn_srcptr poly, slong len, ulong e, nmod_t mod)
void nmod_poly_pow(nmod_poly_t res, const nmod_poly_t poly, ulong e)

Set res to polye\mathit{poly}^e by binary exponentiation; the two pairs of functions are the same. The underscore versions require len≥1\mathit{len} \ge 1 and e≥1e \ge 1, write (len−1)e+1(\mathit{len} - 1) e + 1 coefficients and do not allow aliasing. nmod_poly_pow returns 1 for 000^0, but nmod_poly_pow_binexp returns 0.

More
void _nmod_poly_pow_trunc(nn_ptr res, nn_srcptr poly, ulong e, slong trunc, nmod_t mod)
void nmod_poly_pow_trunc(nmod_poly_t res, const nmod_poly_t poly, ulong e, slong trunc)

Set res to polye mod xtrunc\mathit{poly}^e \bmod x^{\mathit{trunc}} by binary exponentiation with truncated products; the two pairs of functions are the same. The underscore versions read exactly trunc coefficients of poly (zero-pad shorter inputs), require trunc≥1\mathit{trunc} \ge 1 and e≥1e \ge 1, write trunc coefficients and do not allow aliasing.

More

Division#

Division with remainder by BB requires the leading coefficient of BB to be invertible modulo nn; otherwise FLINT_IMPINV is thrown. Division by the zero polynomial throws FLINT_DIVZERO, except modulo n=1n = 1, where nmod_poly_divrem, nmod_poly_div and nmod_poly_divexact return Q=AQ = A and R=0R = 0. Short quotients are computed by schoolbook division; long ones by Newton iteration on the reversed polynomials, which costs a constant number of multiplications. Division with remainder compares the functions and gives examples.

AlgorithmNewton iteration for power series and divisionInverse, quotient, square root, reciprocal square root, exponential and logarithm of power series by Newton iteration with middle products and the Karp–Markstein trick, and polynomial division with remainder via reversed polynomials, as implemented for nmod_poly.

Set QQ and RR to the quotient and remainder of AA by BB, so that A=BQ+RA = BQ + R with deg⁡R<deg⁡B\deg R < \deg B. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1 and writes lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients to QQ and lenB−1\mathit{lenB} - 1 to RR. RR may be the same array as AA; otherwise the outputs must not overlap each other or the inputs.

Full documentation
void _nmod_poly_div(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)

Set QQ to the quotient of AA by BB without computing the remainder. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, writes lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients and does not allow aliasing.

Full documentation
void _nmod_poly_rem(nn_ptr R, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)

Set RR to the remainder of AA by BB. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, writes lenB−1\mathit{lenB} - 1 coefficients and does not allow aliasing. Quotients of length 2, the typical step of the Euclidean algorithm, use a dedicated routine. nmod_poly_rem throws FLINT_DIVZERO for B=0B = 0 even modulo 1.

Full documentation

Set QQ to A/BA / B, assuming that BB divides AA; otherwise the result is meaningless. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, writes lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients and does not allow aliasing.

Full documentation

Set QQ to the quotient of AA by x−cx - c and return the remainder A(c)A(c), by Horner's rule (synthetic division). The value cc must be reduced. The underscore version requires len≥2\mathit{len} \ge 2 (for smaller lengths it returns 0 and writes nothing), writes len−1\mathit{len} - 1 coefficients and allows Q == A.

If BB divides AA, set Q=A/BQ = A / B and return 1; otherwise set Q=0Q = 0 and return 0. The zero polynomial divides only itself. The underscore versions require lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, write lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients and do not allow aliasing.

Full documentation

Removes the largest power pkp^k dividing f from f and returns kk. Requires deg⁡p≥1\deg p \ge 1: for a nonzero constant pp the function does not terminate. For f=0f = 0 it returns 0.

Division with remainder by the schoolbook algorithm, with the same conventions as _nmod_poly_divrem and nmod_poly_divrem.

More

Set QQ to the quotient of AA by BB, given the power series inverse Binv of the reversal of BB (see Computing modulo a fixed polynomial). The quotient is the reversal of rev⁡(A)⋅Binv mod xlenQ\operatorname{rev}(A) \cdot \mathit{Binv} \bmod x^{\mathit{lenQ}}, so Binv must be correct modulo xlenQx^{\mathit{lenQ}}, lenQ=lenA−lenB+1\mathit{lenQ} = \mathit{lenA} - \mathit{lenB} + 1. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, does not read BB, and does not allow QQ to overlap Binv.

More

Set QQ and RR to the quotient and remainder of AA by BB, given Binv as for nmod_poly_div_newton_n_preinv; the remainder is A−BQA - BQ computed by a short product. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1 and does not allow the outputs to overlap the inputs.

More

Power series inversion and division#

These functions compute with power series truncated to length nn, that is, modulo xnx^n. The constant term of the divisor must be invertible modulo nn; otherwise FLINT_IMPINV is thrown. For long series they use Newton iteration, which costs a small constant number of multiplications of length nn. See Power series inversion and division.

Set Qinv to the inverse of the power series QQ modulo xnx^n, that is, Q⋅Qinv≡1(modxn)Q \cdot \mathit{Qinv} \equiv 1 \pmod{x^n}. The underscore version requires Qlen≥1\mathit{Qlen} \ge 1 and n≥1n \ge 1, writes nn coefficients and does not allow aliasing; QQ may be longer than nn. The non-underscore version throws FLINT_DIVZERO if Q=0Q = 0 or n=0n = 0.

Full documentation

The same, by the O(nmin⁡(n,Qlen))O(n \min(n, \mathit{Qlen})) recurrence q0=Q0−1q_0 = Q_0^{-1}, qi=−q0∑j≥1Qjqi−jq_i = -q_0 \sum_{j \ge 1} Q_j q_{i-j}, with each sum computed as a dot product. A binomial Q0+cxkQ_0 + c x^k is inverted directly as a geometric series.

Full documentation

The same as _nmod_poly_inv_series and nmod_poly_inv_series, of which they are aliases; they use Newton iteration only when the length makes it faster.

Full documentation

Set QQ to A/B mod xnA / B \bmod x^n, so that BQ≡A(modxn)BQ \equiv A \pmod{x^n}. The underscore version requires Alen,Blen,n≥1\mathit{Alen}, \mathit{Blen}, n \ge 1, writes nn coefficients and does not allow aliasing. The non-underscore version throws FLINT_DIVZERO if n=0n = 0, B=0B = 0 or B0=0B_0 = 0.

Full documentation

The same by the O(nmin⁡(n,Blen))O(n \min(n, \mathit{Blen})) recurrence qi=B0−1(Ai−∑j≥1Bjqi−j)q_i = B_0^{-1} (A_i - \sum_{j \ge 1} B_j q_{i-j}).

Full documentation

Arithmetic modulo a polynomial#

These functions compute in (Z/nZ)[x]/(f)(\mathbb{Z}/n\mathbb{Z})[x]/(f) for a nonzero ff whose leading coefficient is invertible. Elements are represented by their remainders, polynomials of length less than lenf\mathit{lenf}; the underscore functions usually require them to be zero-padded to length exactly lenf−1\mathit{lenf} - 1. The _preinv variants take the power series inverse finv of the reversal of ff, computed once with nmod_poly_inv_series(finv, rev(f), lenf), which turns every reduction into two products. The guide Computing modulo a fixed polynomial explains these conventions; Exponentiation modulo a polynomial covers exponentiation.

void _nmod_poly_mulmod(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nn_srcptr f, slong lenf, nmod_t mod)
void nmod_poly_mulmod(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, const nmod_poly_t f)

Set res to poly1⋅poly2 mod f\mathit{poly1} \cdot \mathit{poly2} \bmod f, computed as a product followed by _nmod_poly_divrem. The underscore version requires len1,len2≥1\mathit{len1}, \mathit{len2} \ge 1 and len1+len2−1≥lenf\mathit{len1} + \mathit{len2} - 1 \ge \mathit{lenf} (otherwise there is nothing to reduce; use _nmod_poly_mul), writes lenf−1\mathit{lenf} - 1 coefficients and does not allow res to overlap ff. The non-underscore version accepts inputs of any length and throws FLINT_ERROR for f=0f = 0.

void _nmod_poly_mulmod_preinv(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)
void nmod_poly_mulmod_preinv(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, const nmod_poly_t f, const nmod_poly_t finv)

Set res to poly1⋅poly2 mod f\mathit{poly1} \cdot \mathit{poly2} \bmod f, reducing with _nmod_poly_divrem_newton_n_preinv and the precomputed finv. Both factors must be reduced modulo ff: the non-underscore version throws FLINT_ERROR if len1≥lenf\mathit{len1} \ge \mathit{lenf} or len2≥lenf\mathit{len2} \ge \mathit{lenf}. The underscore version also requires len1,len2≥1\mathit{len1}, \mathit{len2} \ge 1 and len1+len2−1≥lenf\mathit{len1} + \mathit{len2} - 1 \ge \mathit{lenf}, writes lenf−1\mathit{lenf} - 1 coefficients and does not allow res to overlap ff or finv.

int _nmod_poly_invmod(ulong * A, const ulong * B, slong lenB, const ulong * P, slong lenP, const nmod_t mod)

If BB is invertible modulo PP, set AA to its inverse and return 1; otherwise return 0, leaving AA undefined. Requires a prime modulus. The non-underscore version reduces BB modulo PP first, returns 0 for B=0B = 0 and throws FLINT_ERROR if lenP<2\mathit{lenP} < 2. The underscore version requires 1≤lenB<lenP1 \le \mathit{lenB} < \mathit{lenP} (zero padding of BB is allowed), writes lenP−1\mathit{lenP} - 1 coefficients and does not allow aliasing. It calls the extended Euclidean algorithm _nmod_poly_gcdinv.

Set res to polye mod f\mathit{poly}^e \bmod f by left-to-right binary exponentiation, reducing each product with _nmod_poly_divrem. The non-underscore versions accept any poly (reducing it first) and e≥0e \ge 0, and throw FLINT_ERROR for f=0f = 0. The underscore versions require lenf≥2\mathit{lenf} \ge 2, poly reduced and zero-padded to length lenf−1\mathit{lenf} - 1, and e≥1e \ge 1; they write lenf−1\mathit{lenf} - 1 coefficients and do not allow aliasing.

Full documentation

The same with a precomputed finv, reducing with _nmod_poly_divrem_newton_n_preinv. These are the functions to use for large ff or many exponentiations modulo the same ff.

Full documentation

Set res to xe mod fx^e \bmod f, given finv. They use sliding-window exponentiation in which a multiplication by xwx^w is a shift followed by a reduction, so each window costs one reduction instead of a full multiplication. The underscore versions require lenf≥3\mathit{lenf} \ge 3 and e≥1e \ge 1 and write lenf−1\mathit{lenf} - 1 coefficients; the non-underscore versions accept e≥0e \ge 0 and any nonzero ff.

Full documentation
void _nmod_poly_powers_mod_preinv_naive(nn_ptr * res, nn_srcptr f, slong flen, slong n, nn_srcptr g, slong glen, nn_srcptr ginv, slong ginvlen, const nmod_t mod)

Set res[i] to fi mod gf^i \bmod g for 0≤i<n0 \le i < n, computing fif^i as f⌊i/2⌋f⌈i/2⌉f^{\lfloor i/2 \rfloor} f^{\lceil i/2 \rceil}. The non-underscore version takes an array of nn initialised polynomials, reduces ff first, and throws FLINT_ERROR for g=0g = 0; for f=0f = 0 or constant gg it sets res[0] to 1 and the others to 0. The underscore version requires 1≤flen<glen1 \le \mathit{flen} < \mathit{glen}, ginv as for _nmod_poly_mulmod_preinv, and nn arrays of glen−1\mathit{glen} - 1 coefficients, all of which are written.

void _nmod_poly_powers_mod_preinv_threaded_pool(nn_ptr * res, nn_srcptr f, slong flen, slong n, nn_srcptr g, slong glen, nn_srcptr ginv, slong ginvlen, const nmod_t mod, thread_pool_handle * threads, slong num_threads)
void _nmod_poly_powers_mod_preinv_threaded(nn_ptr * res, nn_srcptr f, slong flen, slong n, nn_srcptr g, slong glen, nn_srcptr ginv, slong ginvlen, const nmod_t mod)

The same as the naive functions, computed with baby steps and giant steps in parallel: with k=⌊n⌋k = \lfloor \sqrt{n} \rfloor, the powers f0,…,fkf^0, \ldots, f^k and f2k,f3k,…f^{2k}, f^{3k}, \ldots are computed first, and then the threads fill in fik+j=fikfjf^{ik + j} = f^{ik} f^j, taking blocks of kk powers from a shared counter. _nmod_poly_powers_mod_preinv_threaded and nmod_poly_powers_mod_bsgs take their threads from the global pool (see thread_pool.h), the _pool version uses the num_threads threads given.

Preconditioned modular multiplication#

When many products ab mod dab \bmod d are needed with the same aa and dd, data depending on aa can be precomputed so that each product is cheaper than nmod_poly_mulmod_preinv. Two methods are available. The matrix method stores the n×nn \times n matrix of multiplication by aa, whose column ii is axi mod da x^i \bmod d, n=deg⁡dn = \deg d, and computes ab mod dab \bmod d as a matrix-vector product; for small moduli several entries are packed into one word. It costs O(n2)O(n^2) but is very fast for nn up to a few hundred. The Shoup method stores the quotient ⌊axn/d⌋\lfloor a x^n / d \rfloor; then the quotient of abab by dd is the high part of a short product, and ab mod dab \bmod d costs three short products instead of four, by the polynomial analogue of Shoup multiplication [Sho1995].

Precomputed data for multiplication by a fixed aa modulo a fixed dd. It stores shallow references to aa, dd and the inverse of dd, which must stay alive and unchanged while it is used.

The methods: no precomputation (_nmod_poly_mulmod_preinv is called), Shoup's method, and the matrix method.

Initialise precond for multiplication by aa modulo dd with the given method. Require aa reduced modulo dd (alen<dlen\mathit{alen} < \mathit{dlen}) and dinv the power series inverse of the reversal of dd, as for nmod_poly_mulmod_preinv; the matrix method only reads dinv[0]. An invalid method throws FLINT_ERROR.

Like the init_method functions, but choose the method expected to be fastest for num multiplications.

More

Frees the memory used by precond.

Set res to ab mod dab \bmod d for the aa and dd of precond. Require bb reduced modulo dd. The underscore version requires alen,blen≥1\mathit{alen}, \mathit{blen} \ge 1, writes deg⁡d\deg d coefficients (zero-padded) and does not allow res to overlap bb, aa or dd. The non-underscore version allows res to be bb, but not aa.

Greatest common divisor#

All GCD functions require a prime modulus (not checked); a non-invertible leading coefficient met by the Euclidean or the half-GCD algorithm throws FLINT_IMPINV. The non-underscore functions return the monic GCD, with gcd⁡(0,0)=0\gcd(0, 0) = 0, and accept their inputs in any order. Below a cutoff that depends on the bit size of nn the Euclidean algorithm is used, for moduli of FLINT_BITS/2\mathtt{FLINT\_BITS}/2 to FLINT_BITS−2\mathtt{FLINT\_BITS} - 2 bits and lenB≥32\mathit{lenB} \ge 32 in Montgomery arithmetic; above it the half-GCD algorithm [ThullYap1990] computes the GCD in O(M(n)log⁡n)O(M(n) \log n) operations. See Greatest common divisors.

AlgorithmHalf-GCDThe half-gcd algorithm computes the quotients of the first half of the Euclidean remainder sequence from the top halves of the inputs, recursively, giving GCDs, extended GCDs and resultants in O(M(n)log⁡n)O(M(n) \log n) operations; with a correctness proof and FLINT's cutoffs for nmod_poly.

Set GG to a greatest common divisor of AA and BB. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, writes at most lenB\mathit{lenB} coefficients, returns the length of GG, does not make GG monic and does not allow aliasing.

Full documentation

The GCD by the Euclidean algorithm, with the conventions of _nmod_poly_gcd and nmod_poly_gcd. Each step is a call to _nmod_poly_rem, so the cost is O(lenA⋅lenB)O(\mathit{lenA} \cdot \mathit{lenB}).

The Euclidean algorithm in Montgomery arithmetic (nmod_redc_fast, see nmod.h), after a first remainder in the ordinary representation. Require an odd prime modulus n<2FLINT_BITS−2n < 2^{\mathtt{FLINT\_BITS} - 2}, which is not checked.

The condition under which _nmod_poly_gcd and _nmod_poly_resultant use the Montgomery version of the Euclidean algorithm: lenB≥32\mathit{lenB} \ge 32 and FLINT_BITS/2≤\mathtt{FLINT\_BITS}/2 \le NMOD_BITS(mod) ≤FLINT_BITS−2\le \mathtt{FLINT\_BITS} - 2. It does not check that nn is odd, so an even modulus in this range gives an exception or a crash; such moduli are not prime and therefore not supported anyway.

The GCD by the half-GCD algorithm, with the conventions of _nmod_poly_gcd and nmod_poly_gcd. Its complexity is O(M(n)log⁡n)O(M(n) \log n), where M(n)M(n) is the cost of a multiplication of length nn.

More
slong _nmod_poly_hgcd(nn_ptr * M, slong * lenM, nn_ptr A, slong * lenA, nn_ptr B, slong * lenB, nn_srcptr a, slong lena, nn_srcptr b, slong lenb, nmod_t mod)

The half-GCD step. For deg⁡a>deg⁡b\deg a > \deg b, compute consecutive remainders A,BA, B of the Euclidean remainder sequence of a,ba, b with deg⁡A≥deg⁡(a)/2>deg⁡B\deg A \ge \deg(a)/2 > \deg B and the matrix

M=(m11m12m21m22),(ab)=M(AB),M = \begin{pmatrix} m_{11} & m_{12} \\ m_{21} & m_{22} \end{pmatrix}, \qquad \begin{pmatrix} a \\ b \end{pmatrix} = M \begin{pmatrix} A \\ B \end{pmatrix},

the product of the matrices (qi110)\left(\begin{smallmatrix} q_i & 1 \\ 1 & 0 \end{smallmatrix}\right) for the quotients qiq_i of these steps. Return det⁡M=±1\det M = \pm 1.

Full documentation

A reference implementation of nmod_poly_hgcd by repeated division with remainder, for testing. Same contract; no aliasing is allowed.

Return the tuned cutoffs for the bit size of the modulus: the length below which the half-GCD recursion uses Euclidean steps (60 to 244), the length below which the outer loop of the half-GCD GCD switches to the Euclidean algorithm (310 to 1585), and the length of BB from which _nmod_poly_gcd (470 to 2199) and _nmod_poly_xgcd (72 to 388) use the half-GCD algorithm.

Compute the GCD GG of AA and BB and cofactors S,TS, T with SA+TB=GSA + TB = G. The non-underscore version makes GG monic; for B≠0B \ne 0 the cofactors satisfy deg⁡S<max⁡(deg⁡B−deg⁡G,1)\deg S < \max(\deg B - \deg G, 1) and deg⁡T<max⁡(deg⁡A−deg⁡G,1)\deg T < \max(\deg A - \deg G, 1), and for B=0B = 0 it returns S=lc⁡(A)−1S = \operatorname{lc}(A)^{-1}, T=0T = 0. GG, SS and TT must be distinct objects.

Full documentation

The extended GCD by the Euclidean and by the half-GCD algorithm, with the conventions of _nmod_poly_xgcd and nmod_poly_xgcd.

slong _nmod_poly_gcdinv(ulong * G, ulong * S, const ulong * A, slong lenA, const ulong * B, slong lenB, const nmod_t mod)

Compute G=gcd⁡(A,B)G = \gcd(A, B) and SS with G≡SA(modB)G \equiv SA \pmod B and deg⁡S<deg⁡B−deg⁡G\deg S < \deg B - \deg G, without the cofactor of BB. If gcd⁡(A,B)=1\gcd(A, B) = 1, then S=A−1 mod BS = A^{-1} \bmod B. The non-underscore version requires lenB≥2\mathit{lenB} \ge 2 (otherwise it throws FLINT_ERROR), reduces AA modulo BB first, makes GG monic and returns G=S=0G = S = 0 if BB divides AA. The underscore version requires 1≤lenA<lenB1 \le \mathit{lenA} < \mathit{lenB}, writes at most lenA coefficients to GG and lenB−1\mathit{lenB} - 1 to SS, returns the length of GG and does not make GG monic.

Full documentation

Resultant and discriminant#

The resultant of f=a∏i=1m(x−αi)f = a \prod_{i=1}^{m} (x - \alpha_i) and g=b∏j=1k(x−βj)g = b \prod_{j=1}^{k} (x - \beta_j) is

res⁡(f,g)=akbm∏i,j(αi−βj)=ak∏ig(αi),\operatorname{res}(f, g) = a^{k} b^{m} \prod_{i,j} (\alpha_i - \beta_j) = a^{k} \prod_{i} g(\alpha_i),

the determinant of the Sylvester matrix. It is zero exactly when ff and gg have a common factor. These functions require a prime modulus (not checked) and return 0 if either polynomial is zero. See Resultants and discriminants.

Return res⁡(f,g)\operatorname{res}(f, g). The underscore version requires len1≥len2≥1\mathit{len1} \ge \mathit{len2} \ge 1.

Full documentation

The resultant by the Euclidean algorithm, using res⁡(f,g)=(−1)deg⁡fdeg⁡glc⁡(g)deg⁡f−deg⁡rres⁡(g,r)\operatorname{res}(f, g) = (-1)^{\deg f \deg g} \operatorname{lc}(g)^{\deg f - \deg r} \operatorname{res}(g, r) for r=f mod gr = f \bmod g.

Full documentation

The resultant by the half-GCD algorithm, in O(M(n)log⁡n)O(M(n) \log n) operations.

Full documentation

Return the discriminant of ff of degree dd,

disc⁡(f)=(−1)d(d−1)/2lc⁡(f)−1res⁡(f,f′)=lc⁡(f)2d−2∏i<j(αi−αj)2,\operatorname{disc}(f) = (-1)^{d(d-1)/2} \operatorname{lc}(f)^{-1} \operatorname{res}(f, f') = \operatorname{lc}(f)^{2d - 2} \prod_{i < j} (\alpha_i - \alpha_j)^2,

where the power of lc⁡(f)\operatorname{lc}(f) is adjusted if deg⁡f′<d−1\deg f' < d - 1 (when the characteristic divides dd). The discriminant is 0 for constants and when f′=0f' = 0. The underscore version requires len≥2\mathit{len} \ge 2.

Full documentation

Derivative and integral#

Set x_prime to the derivative of x. The underscore version requires len≥1\mathit{len} \ge 1, writes len−1\mathit{len} - 1 coefficients and allows x_prime == x.

Set x_int to the integral of x with constant term 0. The integers 1,…,deg⁡x+11, \ldots, \deg x + 1 must be invertible modulo nn, for example nn prime and n>deg⁡x+1n > \deg x + 1; otherwise FLINT_IMPINV is thrown. Here len is the length of the output: the underscore version reads len−1\mathit{len} - 1 coefficients, writes len coefficients, requires len≥1\mathit{len} \ge 1 and allows x_int == x. It needs only one modular inversion.

Evaluation#

Return poly(c)\mathit{poly}(c) for reduced cc. Any length, including 0, is allowed.

More

Return poly(c)\mathit{poly}(c) by Horner's rule, and by rectangular splitting: with m=min⁡(⌊len⌋+1,1024)m = \min(\lfloor\sqrt{\mathit{len}}\rfloor + 1, 1024), the powers c,…,cmc, \ldots, c^m are computed once, each block of mm coefficients is evaluated by a dot product (see Computing dot products), and the blocks are combined by Horner's rule in cmc^m. The dot products accumulate without intermediate reductions, which makes rectangular splitting faster than Horner's rule for long polynomials although it does the same number of multiplications.

Evaluate poly at cc modulo modn by Horner's rule with Shoup multiplication, given c_precomp = n_mulmod_precomp_shoup(c, modn). Require c<modn<2FLINT_BITS−1c < \mathit{modn} < 2^{\mathtt{FLINT\_BITS} - 1}.

More

Set dest to the matrix poly(c)\mathit{poly}(c), for a square matrix cc with the modulus of poly; dest must have the same dimensions and may be c. The Horner version uses deg⁡(poly)\deg(\mathit{poly}) matrix multiplications, the Paterson–Stockmeyer version [PS1973] about 2deg⁡2\sqrt{\deg} matrix multiplications and O(deg⁡)O(\deg) scalar multiply-adds. nmod_poly_evaluate_mat uses Horner's rule if len<5\mathit{len} < 5 or len⋅r<425\mathit{len} \cdot r < 425 for an r×rr \times r matrix, and Paterson–Stockmeyer otherwise.

More

Sets dest to mat+cI\mathit{mat} + cI for a square matrix mat and reduced cc, the step of Horner's rule above. dest may be mat.

Multipoint evaluation and interpolation#

Evaluating a polynomial of length nn at nn points, or interpolating through nn points, takes O(n2)O(n^2) operations with Horner's rule or Lagrange interpolation, and O(M(n)log⁡n)O(M(n) \log n) operations with a subproduct tree: the products ∏(x−xi)\prod (x - x_i) over the leaves of a binary tree on the points. Evaluation reduces the polynomial down the tree, interpolation combines the values up the tree. Interpolation needs the xix_i to be distinct, with invertible differences (for example, nn prime). See Multipoint evaluation and interpolation.

AlgorithmMultipoint evaluation and interpolationEvaluation of a polynomial at many points and interpolation through many points in O(M(n)log⁡n)O(M(n) \log n) operations with the subproduct tree and the remainder tree, and in O(M(n)) for points in geometric progression with Bluestein's chirp transform and the method of Bostan and Schost.

Set ys[i] to poly(xs[i])\mathit{poly}(\mathit{xs}[i]) for 0≤i<olen0 \le i < \mathit{olen}, for reduced points. Polynomials of length less than 32 are evaluated point by point with _nmod_poly_evaluate_nmod, longer ones with a subproduct tree.

Full documentation

The same, evaluating at each point with _nmod_poly_evaluate_nmod.

The same with a temporary subproduct tree.

Full documentation
void _nmod_poly_evaluate_nmod_vec_fast_precomp(nn_ptr vs, nn_srcptr poly, slong ilen, const nn_ptr * tree, slong olen, nmod_t mod)

Evaluates (poly, ilen) at the olen points of the subproduct tree tree, built with _nmod_poly_tree_build. The polynomial may be longer or shorter than the number of points; it is first reduced modulo the products at the highest useful level of the tree, and the remainders are then reduced down the tree.

Allocate and free a subproduct tree for len points. For len = 0, _nmod_poly_tree_alloc returns NULL.

void _nmod_poly_tree_build(nn_ptr * tree, nn_srcptr roots, slong len, nmod_t mod)

Builds the subproduct tree of the monic linear factors x−rix - r_i, 0≤i<len0 \le i < \mathit{len}, in the space allocated by _nmod_poly_tree_alloc.

Full documentation

Sets w[i] to the barycentric weight 1/∏j≠i(xi−xj)=1/P′(xi)1 / \prod_{j \ne i} (x_i - x_j) = 1 / P'(x_i), where P=∏j(x−xj)P = \prod_j (x - x_j) for the points of tree.

Sets (poly, len) to the polynomial of length at most len taking the values ys at the points of tree, given the weights from _nmod_poly_interpolation_weights, by combining the scaled values yiwiy_i w_i up the tree (fast Lagrange interpolation). Writes len coefficients.

Set poly to the unique polynomial of length at most len with poly(xi)=yi\mathit{poly}(x_i) = y_i for 0≤i<len0 \le i < \mathit{len}. The points must be distinct and all values reduced. Uses the Newton form for len<6\mathit{len} < 6, the barycentric form for len<16\mathit{len} < 16 and fast interpolation otherwise. The underscore version requires len≥1\mathit{len} \ge 1, writes len coefficients and does not allow poly to overlap xs or ys.

Full documentation

The same by fast Lagrange interpolation with a temporary subproduct tree, in O(M(len)log⁡len)O(M(\mathit{len}) \log \mathit{len}) operations.

Full documentation

The same by divided differences, followed by a conversion from the Newton basis to the monomial basis. It uses O(len2)O(\mathit{len}^2) multiplications and O(len2)O(\mathit{len}^2) modular inversions.

The same by the Lagrange formula ∑iyiwiP(x)/(x−xi)\sum_i y_i w_i P(x)/(x - x_i), with P=∏(x−xi)P = \prod (x - x_i) and wiw_i as above, in O(len2)O(\mathit{len}^2) multiplications and len inversions.

Set poly to ∏i=0n−1(x−xi)\prod_{i=0}^{n-1} (x - x_i), for reduced xix_i. The underscore version writes n+1n + 1 coefficients and does not allow aliasing. Uses the quadratic algorithm for n<20n < 20 and balanced products above.

Geometric progressions#

Evaluation and interpolation at the points of a geometric progression 1,q,q2,…1, q, q^2, \ldots cost O(M(n))O(M(n)) instead of O(M(n)log⁡n)O(M(n) \log n): evaluation is a single middle product by Bluestein's chirp transform [Blu1970] [RSR1969], using ij=(i+j2)−(i2)−(j2)ij = \binom{i+j}{2} - \binom{i}{2} - \binom{j}{2}, and interpolation is two products [BS2005]. The functions take rr with q=r2q = r^2, so that qi2/2=ri2q^{i^2/2} = r^{i^2} needs no square root, and use the points 1,r2,r4,…1, r^2, r^4, \ldots. The value rr must be reduced and invertible modulo nn. For interpolation and extrapolation the points must be distinct with r2k−1r^{2k} - 1 invertible, which for prime nn means that the multiplicative order of r2r^2 exceeds the number of points. See Geometric progressions.

Precomputed data for evaluation, interpolation and extrapolation at the points 1,r2,…,r2(len−1)1, r^2, \ldots, r^{2(\mathit{len} - 1)}: scaling vectors, the polynomials to multiply by and, optionally, their fft_small transforms. The functions using it only read it, so several threads can use one progression at the same time.

Initialise G for the points 1,r2,…,r2(len−1)1, r^2, \ldots, r^{2(\mathit{len}-1)}. len must be at least the number of points and at least the length of the polynomials used. nmod_geometric_progression_init prepares evaluation, interpolation and extrapolation; the second function only the functionalities selected by the bits of function: bit 0 evaluation, bit 1 interpolation, bit 2 extrapolation, and bit 3 stored transforms.

More

Stores the fft_small transforms described above for the functionalities of G, with a separate bound, at most G->len, for each: evaluation of polynomials of length at most ev_len, interpolation from at most int_len points, and extrapolation from at most ext_len values. A bound 0 removes the stored transforms of the functionality and a negative bound keeps them unchanged. Smaller bounds give shorter transforms for evaluation (ev_len+len−1\mathit{ev\_len} + \mathit{len} - 1 instead of 2len−12 \mathit{len} - 1) and interpolation (about 2 int_len2\,\mathit{int\_len}), and may need fewer primes; the extrapolation transforms have length len−1\mathit{len} - 1 whatever ext_len, which only bounds the number of primes. Longer inputs remain possible without the stored transforms. Must not be called while other threads use G.

Sets vs[i] to poly(r2i)\mathit{poly}(r^{2i}) for 0≤i<olen0 \le i < \mathit{olen}, using G prepared for evaluation. Requires ilen,olen≤\mathit{ilen}, \mathit{olen} \le G->len.

More

The same with a temporary precomputation for evaluation.

The same by evaluating at each point with _nmod_poly_evaluate_nmod. No condition on rr.

Set poly to the polynomial of length at most len taking the values v[i] at r2ir^{2i}, 0≤i<len0 \le i < \mathit{len}, using G prepared for interpolation. Requires 1≤len≤1 \le \mathit{len} \le G->len. The underscore version writes len coefficients and does not allow poly to overlap v.

More

The same with a temporary precomputation for interpolation.

void nmod_poly_extrapolate_geometric(nn_ptr oval, slong olen, nn_srcptr ival, slong ilen, slong offset, ulong r, nmod_t mod)

Given the values ival of a polynomial ff of degree less than ilen\mathit{ilen} at ilen consecutive points of the progression, compute its values oval at olen consecutive points starting offset positions later, without computing ff. The points must not overlap: offset≥ilen\mathit{offset} \ge \mathit{ilen} (forward) or offset+olen≤0\mathit{offset} + \mathit{olen} \le 0 (backward).

More

Composition#

Composition f(g)f(g) and the Taylor shift f(x+c)f(x + c); see Composition and Taylor shifts.

void _nmod_poly_compose(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)
void nmod_poly_compose(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)

Set res to the composition poly1(poly2)\mathit{poly1}(\mathit{poly2}). The underscore version requires len1,len2≥1\mathit{len1}, \mathit{len2} \ge 1, writes (len1−1)(len2−1)+1(\mathit{len1} - 1)(\mathit{len2} - 1) + 1 coefficients and does not allow aliasing.

Full documentation
void _nmod_poly_compose_horner(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)
void nmod_poly_compose_horner(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)

The composition by Horner's rule, with the conventions of _nmod_poly_compose.

Full documentation

Set g(x)=f(x+c)g(x) = f(x + c), for reduced cc; the underscore version works in place on (poly, len). Uses Horner's rule for len<100\mathit{len} < 100 or len>n\mathit{len} > n, and for c=±1c = \pm 1 and len<1000\mathit{len} < 1000, and the convolution method otherwise, which requires (len−1)!(\mathit{len} - 1)! to be invertible modulo nn (for prime nn, guaranteed by len≤n\mathit{len} \le n); otherwise FLINT_IMPINV is thrown.

Full documentation

The Taylor shift by Horner's rule, with O(len2)O(\mathit{len}^2) additions and multiplications. Works for every modulus.

Full documentation

The Taylor shift as one product of length len, using ∑kfk(x+c)k=∑jxjj!∑kk! fkck−j(k−j)!\sum_k f_k (x + c)^k = \sum_j \frac{x^j}{j!} \sum_k k!\, f_k \frac{c^{k-j}}{(k-j)!} [ASU1975] [GG1997], in O(M(len))O(M(\mathit{len})) operations. Requires (len−1)!(\mathit{len} - 1)! to be invertible modulo nn.

Full documentation

Modular composition#

Modular composition computes f(g) mod hf(g) \bmod h. By the algorithm of Brent and Kung [BrentKung1978] it costs O(n1/2M(n)+n(ω+1)/2)O(n^{1/2} M(n) + n^{(\omega + 1)/2}) operations for deg⁡h=n\deg h = n, using a matrix product of size n×n\sqrt{n} \times \sqrt{n} by n×n\sqrt{n} \times n. With m=⌊n⌋+1m = \lfloor \sqrt n \rfloor + 1, the m×nm \times n matrix AA holding g0,…,gm−1 mod hg^0, \ldots, g^{m-1} \bmod h in its rows can be precomputed and reused for many ff. All functions require h≠0h \ne 0 with invertible leading coefficient and allow res to be any input (the non-underscore versions). See Modular composition.

AlgorithmComposition and modular compositionComputing f(g)f(g), f(g) mod xnf(g) \bmod x^n and f(g) mod hf(g) \bmod h by Horner's rule, divide and conquer, Taylor shifts, the baby-step giant-step method of Brent and Kung, and the algorithm of Kinoshita and Li, with the choices made by nmod_poly.

Set res to f(g) mod hf(g) \bmod h. The non-underscore version accepts any ff and gg and throws FLINT_DIVZERO for h=0h = 0. The underscore version requires lenh≥2\mathit{lenh} \ge 2, lenf≥1\mathit{lenf} \ge 1 and gg reduced and zero-padded to length lenh−1\mathit{lenh} - 1, writes lenh−1\mathit{lenh} - 1 coefficients and does not allow aliasing. It uses Horner's rule if lenh<8\mathit{lenh} < 8 or lenf≥lenh\mathit{lenf} \ge \mathit{lenh}, and the Brent–Kung algorithm otherwise.

Full documentation

Modular composition by Horner's rule, with lenf−1\mathit{lenf} - 1 multiplications modulo hh, and the conventions of _nmod_poly_compose_mod.

Full documentation

Modular composition by the Brent–Kung algorithm, with the conventions of _nmod_poly_compose_mod. Requires lenf<lenh\mathit{lenf} < \mathit{lenh} (deg⁡f<deg⁡h\deg f < \deg h); the non-underscore version throws FLINT_ERROR otherwise.

Full documentation
void _nmod_poly_compose_mod_brent_kung_preinv(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, nn_srcptr poly3, slong len3, nn_srcptr poly3inv, slong len3inv, nmod_t mod)
void nmod_poly_compose_mod_brent_kung_preinv(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, const nmod_poly_t poly3, const nmod_poly_t poly3inv)

Set res to poly1(poly2) mod poly3\mathit{poly1}(\mathit{poly2}) \bmod \mathit{poly3} by the Brent–Kung algorithm, given the inverse poly3inv of the reversal of poly3 as for nmod_poly_mulmod_preinv. Requires len1<len3\mathit{len1} < \mathit{len3}; the underscore version also requires poly2 reduced and zero-padded to length len3−1\mathit{len3} - 1.

Full documentation
void _nmod_poly_precompute_matrix(nmod_mat_t A, nn_srcptr poly1, nn_srcptr poly2, slong len2, nn_srcptr poly2inv, slong len2inv, nmod_t mod)
void nmod_poly_precompute_matrix(nmod_mat_t A, const nmod_poly_t poly1, const nmod_poly_t poly2, const nmod_poly_t poly2inv)

Set the rows of the m×nm \times n matrix AA to poly1i mod poly2\mathit{poly1}^i \bmod \mathit{poly2} for 0≤i<m0 \le i < m, where n=deg⁡poly2n = \deg \mathit{poly2} and m=⌊n⌋+1m = \lfloor \sqrt{n} \rfloor + 1, given the inverse poly2inv of the reversal of poly2. AA must be initialised with these dimensions (the non-underscore version throws FLINT_ERROR otherwise). The underscore version requires poly1 reduced and zero-padded to length nn.

Full documentation
void _nmod_poly_compose_mod_brent_kung_precomp_preinv(nn_ptr res, nn_srcptr poly1, slong len1, const nmod_mat_t A, nn_srcptr poly3, slong len3, nn_srcptr poly3inv, slong len3inv, nmod_t mod)

Set res to poly1(g) mod poly3\mathit{poly1}(g) \bmod \mathit{poly3}, where AA is the matrix computed by nmod_poly_precompute_matrix for gg and poly3. Requires len1<len3\mathit{len1} < \mathit{len3}. This is the function to use for many compositions with the same gg and modulus, as in the computation of Frobenius powers in polynomial factorisation [GatSho1992] [KalSho1998].

Full documentation

Initialises AA as an m×nm \times n matrix, n=deg⁡fn = \deg f, m=⌊n⌋+1m = \lfloor \sqrt n \rfloor + 1, and sets row 0 to 1 and row ii to row ii of BB reduced modulo ff for 1≤i<m1 \le i < m. AA must not be initialised before the call; BB needs at least mm rows and at least deg⁡f+1\deg f + 1 columns.

void _nmod_poly_mod_matrix_rows_evaluate(nn_ptr res, const nmod_mat_t A, nn_srcptr h, slong n, nn_srcptr poly3, slong len3, nn_srcptr poly3inv, slong len3inv, nmod_t mod)

Sets (res, n) to ∑iAihi mod poly3\sum_{i} A_i h^i \bmod \mathit{poly3}, where AiA_i is row ii of the d×nd \times n matrix AA, h has length nn and len3=n+1\mathit{len3} = n + 1. This is the last step of the Brent–Kung algorithm, with h=gmh = g^m; it uses Horner's rule for d≤10d \le 10 and rectangular splitting otherwise.

Power series composition and reversion#

void _nmod_poly_compose_series(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong n, nmod_t mod)
void nmod_poly_compose_series(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)

Set res to poly1(poly2) mod xn\mathit{poly1}(\mathit{poly2}) \bmod x^n, where poly2 must have constant term 0 (the non-underscore version throws FLINT_ERROR otherwise). The underscore version requires 0<len1,len2≤n0 < \mathit{len1}, \mathit{len2} \le n, writes nn coefficients and does not allow aliasing.

More

Set Qinv to the compositional inverse of the power series QQ modulo xnx^n, so that Q(Qinv(x))=Qinv(Q(x))=x mod xnQ(\mathit{Qinv}(x)) = \mathit{Qinv}(Q(x)) = x \bmod x^n. Requires Q0=0Q_0 = 0 and Q1Q_1 invertible; the non-underscore version throws FLINT_ERROR otherwise. The underscore version writes nn coefficients and does not allow aliasing.

More

Square roots#

Set gg to h\sqrt{h} and 1/h1/\sqrt{h} modulo xnx^n. The constant term of hh must be a nonzero square modulo a prime n≠2n \ne 2 (it is usually 1), and its square root is chosen by nmod_sqrt; otherwise an exception is thrown. The underscore versions require hlen,n≥1\mathit{hlen}, n \ge 1, write nn coefficients and do not allow aliasing.

More

If aa is the square of a polynomial, set bb to a square root and return 1; otherwise return 0 (and set b=0b = 0). Requires a prime modulus. The underscore version requires len≥1\mathit{len} \ge 1, writes len/2+1\mathit{len} / 2 + 1 coefficients and does not allow aliasing.

More

Power sums#

The power sums of a polynomial ff with roots α1,…,αd\alpha_1, \ldots, \alpha_d (with multiplicity, in an algebraic closure) are pk=∑iαikp_k = \sum_i \alpha_i^k. They determine ff if d!d! is invertible, by Newton's identities kek=∑i=1k(−1)i−1ek−ipik e_k = \sum_{i=1}^{k} (-1)^{i-1} e_{k-i} p_i, and can be computed in O(M(d))O(M(d)) operations from the series ∑k≥0pkxk=d−xf~′(x)/f~(x)\sum_{k \ge 0} p_k x^k = d - x \tilde f'(x)/\tilde f(x), where f~\tilde f is the reversal of ff [Sch1982b] [BFSS2006]. Here the power sum series of ff is ∑k≥0pkxk\sum_{k \ge 0} p_k x^k with p0=dp_0 = d.

Set res to ∑k=0n−1pkxk\sum_{k=0}^{n-1} p_k x^k. The non-underscore version accepts any nonzero poly with invertible leading coefficient (throwing FLINT_ERROR for zero) and handles factors xkx^k. The underscore version requires poly monic and writes nn coefficients. Uses Newton's identities for 10n<len+7510 n < \mathit{len} + 75 and the series formula otherwise.

The power sums by Newton's identities, in O(n⋅len)O(n \cdot \mathit{len}) operations, and by the series formula with one power series division, in O(M(n))O(M(n)) operations. The underscore versions require poly monic.

Set res to the monic polynomial of degree d=Q0d = Q_0 whose power sum series is QQ (modulo xlenx^{\mathit{len}}, the higher power sums being determined by dd of them). Requires 1,…,d1, \ldots, d invertible modulo nn. For Q=0Q = 0 the result is 1. The underscore version writes d+1d + 1 coefficients. Uses Newton's identities if n≤12n \le 12 or d≤10d \le 10 and the exponential formula f~=exp⁡(∫(d−Q)/x)\tilde f = \exp(\int (d - Q)/x) otherwise.

The same by Newton's identities, in O(d2)O(d^2) operations, and by the exponential formula, in O(M(d))O(M(d)) operations.

Elementary functions of power series#

For a power series hh these functions compute f(h) mod xnf(h) \bmod x^n, where

exp⁡(h)=∑k≥0hkk!,log⁡(h)=∫h′h,atan⁡(h)=∫h′1+h2,atanh⁡(h)=∫h′1−h2,\exp(h) = \sum_{k \ge 0} \frac{h^k}{k!}, \quad \log(h) = \int \frac{h'}{h}, \quad \operatorname{atan}(h) = \int \frac{h'}{1 + h^2}, \quad \operatorname{atanh}(h) = \int \frac{h'}{1 - h^2},
asin⁡(h)=∫h′1−h2,asinh⁡(h)=∫h′1+h2,\operatorname{asin}(h) = \int \frac{h'}{\sqrt{1 - h^2}}, \quad \operatorname{asinh}(h) = \int \frac{h'}{\sqrt{1 + h^2}},

with integration constants 0, and the trigonometric and hyperbolic functions are defined by the usual relations to exp⁡\exp. The constant term of hh must be 1 for log⁡\log and 0 for all other functions; the non-underscore functions throw FLINT_ERROR otherwise. The coefficients involve 1/k1/k for k<nk < n, so the modulus must be a prime p≥np \ge n, and also p>2p > 2; this is not checked. All functions cost O(M(n))O(M(n)) operations for large nn, typically with Newton iteration [HZ2004] [BZ2011], and use quadratic algorithms for small nn. The underscore versions require hlen,n≥1\mathit{hlen}, n \ge 1, write nn coefficients, and allow gg to be the same array as hh unless stated otherwise.

Set f=exp⁡(h) mod xnf = \exp(h) \bmod x^n.

More

Sets f=exp⁡(h)f = \exp(h) and g=exp⁡(−h)=1/fg = \exp(-h) = 1/f modulo xnx^n, currently by _nmod_poly_exp_series followed by _nmod_poly_inv_series. Requires hlen≤n\mathit{hlen} \le n and does not allow aliasing.

Set res=log⁡(f) mod xn\mathit{res} = \log(f) \bmod x^n, for ff with constant term 1, as the integral of f′/ff'/f.

Set gg to atan⁡(h)\operatorname{atan}(h), atanh⁡(h)\operatorname{atanh}(h), asin⁡(h)\operatorname{asin}(h) and asinh⁡(h)\operatorname{asinh}(h) modulo xnx^n, from the integrals above.

Set gg to sin⁡(h)\sin(h), cos⁡(h)\cos(h), tan⁡(h)\tan(h) and tanh⁡(h)\tanh(h) modulo xnx^n.

Set gg to sinh⁡(h)=(eh−e−h)/2\sinh(h) = (e^h - e^{-h})/2 and cosh⁡(h)=(eh+e−h)/2\cosh(h) = (e^h + e^{-h})/2 modulo xnx^n, using _nmod_poly_exp_expinv_series. The underscore versions read exactly nn coefficients of hh (zero-pad shorter inputs) and do not allow aliasing.

Roots#

Root finding and factorisation in general are in nmod_poly_factor.h (nmod_poly_roots, nmod_poly_factor). The function here is a fast path for polynomials that are expected to split into distinct linear factors, as in sparse interpolation and the decoding of Reed–Solomon codes (see Finding roots that are expected to be distinct and Decoding Reed–Solomon codes). The algorithms for roots over finite fields are described in Roots of polynomials over finite fields.

If the nonzero polynomial PP of degree dd has dd distinct nonzero roots modulo the prime nn (not checked), write them to roots[0], ..., roots[d - 1] in no particular order and return 1; otherwise return 0, in which case roots may have been partly written. Constants give 1 and no roots. For n=2n = 2 the result is 0 for d≥2d \ge 2.

Full documentation

For monic ff of degree at least 2 with deg⁡f\deg f distinct nonzero roots modulo an odd prime, find a factorisation f=abf = ab with 1≤deg⁡b≤deg⁡a1 \le \deg b \le \deg a by trying random δ\delta until gcd⁡((x+δ)(n−1)/2−1,f)\gcd((x + \delta)^{(n-1)/2} - 1, f) is a proper factor. t and t2 are temporaries.

Full documentation

Irreducible and Conway polynomials#

Sets res to a monic irreducible polynomial of degree n≥1n \ge 1 over the prime field Fp\mathbb{F}_p, pp the modulus of res, with the least possible number of nonzero terms: a binomial xn+ax^n + a if one exists, otherwise a trinomial, a tetranomial or a pentanomial. Throws FLINT_ERROR if none of these exists; it is conjectured that a tetranomial (p>2p > 2) or pentanomial (p=2p = 2) always does.

More
int _nmod_poly_conway(nn_ptr op, ulong prime, slong deg)

If FLINT's compressed copy of Lübeck's tables [Lüb2004] contains the Conway polynomial Cp,dC_{p,d} for pp = prime and dd = deg, writes its d+1d + 1 coefficients to op and returns 1; otherwise returns 0 (see Defining polynomials). The tables cover the primes below 109988, with all tabulated degrees for p<260p < 260 and degree bounds that decrease with pp above (12 for p<300p < 300, then 9, 6, 4).

ulong _nmod_poly_conway_rand(slong * degree, flint_rand_t state, int type)

Returns a random prime pp and sets degree to a random dd such that _nmod_poly_conway(op, p, d) succeeds, for test code. For type 0 the pair is any tabulated one, for 1 the degree is less than 15, for 2 the prime is less than 2102^{10}, and for 3 both. Other values of type throw FLINT_ERROR.

Inflation and deflation#

void nmod_poly_inflate(nmod_poly_t result, const nmod_poly_t input, slong inflation)

Sets result to p(xk)p(x^k), where pp is input and kk = inflation ≥0\ge 0. For k=0k = 0 the result is the constant p(1)p(1).

void nmod_poly_deflate(nmod_poly_t result, const nmod_poly_t input, slong deflation)

Sets result to p(x1/k)p(x^{1/k}), where pp is input and kk = deflation ≥1\ge 1 must divide the exponent of every nonzero term (not checked). Throws FLINT_DIVZERO for k=0k = 0.

Returns the largest kk such that input is a polynomial in xkx^k, that is, the GCD of the exponents of its nonzero terms. Returns 0 for the zero polynomial and 1 for constants.

Chinese remaindering#

Given pairwise coprime moduli m0,…,ml−1m_0, \ldots, m_{l-1} and values viv_i, these functions find the polynomial rr of least degree with r≡vi(modmi)r \equiv v_i \pmod{m_i}. The moduli are combined pairwise along a binary tree sorted by degree; each node stores an idempotent II with I≡1I \equiv 1 modulo one child and I≡0I \equiv 0 modulo the other, and computes A=B+I(C−B) mod MA = B + I(C - B) \bmod M. All polynomials must have the same prime modulus.

Precomputed data for Chinese remaindering with fixed moduli: a straight line program of instructions _nmod_poly_multi_crt_prog_instr.

One instruction A=B+I(C−B) mod MA = B + I(C - B) \bmod M of the program, with the indices of AA, BB and CC (negative indices refer to the inputs), the idempotent II and the modulus MM.

Prepare CRT for the len≥1\mathit{len} \ge 1 moduli, given as an array of polynomials or of pointers. Return 1 on success, which happens if and only if either len=1\mathit{len} = 1 and the modulus is nonzero, or all moduli have positive degree and are pairwise coprime. On failure (0), later calls with CRT give undefined output.

Set output to the polynomial of least degree congruent to values[i] modulo the ii-th modulus of CRT, for all ii. The values need not be reduced.

int nmod_poly_multi_crt(nmod_poly_t output, const nmod_poly_struct * moduli, const nmod_poly_struct * values, slong len)

The same without a separate precomputation. Returns the value of nmod_poly_multi_crt_precompute; on failure the output is undefined.

void _nmod_poly_multi_crt_run_p(nmod_poly_struct * outputs, const nmod_poly_multi_crt_t CRT, const nmod_poly_struct * const * inputs)

Run the program of CRT with caller-supplied temporaries: outputs must be an array of at least _nmod_poly_multi_crt_local_size(CRT) initialised polynomials with the right modulus, and the result is placed in outputs[0]. Since CRT is only read, several threads can run it with their own outputs.

Berlekamp–Massey algorithm#

The Berlekamp–Massey algorithm [Ber1968] [Mas1969] finds the shortest linear recurrence satisfied by a sequence. FLINT's implementation views it as a partial extended Euclidean algorithm [SKHN1975]: after mm points a1,…,ama_1, \ldots, a_m have been added, nmod_berlekamp_massey_reduce computes polynomials U,V,RU, V, R of the extended Euclidean remainder sequence of xmx^m and S=a1xm−1+a2xm−2+⋯+amS = a_1 x^{m-1} + a_2 x^{m-2} + \cdots + a_m with

Uxm+VS=R,deg⁡U<deg⁡V≤m/2,deg⁡R<m/2.U x^m + V S = R, \qquad \deg U < \deg V \le m/2, \qquad \deg R < m/2.

Then ∑i≥1aix−i=−U/V+R/(Vxm)\sum_{i \ge 1} a_i x^{-i} = -U/V + R/(V x^m), so writing V=∑ivixiV = \sum_i v_i x^i, the recurrence ∑iviaj+i=0\sum_i v_i a_{j+i} = 0 holds for 1≤j<m−deg⁡R1 \le j < m - \deg R. If deg⁡R<deg⁡V\deg R < \deg V, the recurrence holds for the whole sequence (1≤j≤m−deg⁡V1 \le j \le m - \deg V), and VV is, up to a constant factor, the minimal polynomial (characteristic polynomial of the shortest recurrence) of the sequence; otherwise more points are needed. Unlike fmpz_mod_poly_minpoly, which returns a polynomial of least degree annihilating all mm points, whose degree can be close to mm and which is then not determined uniquely, VV has degree at most m/2m/2. The modulus must be prime. See Decoding Reed–Solomon codes for an application.

The state of the algorithm: the points added so far and the polynomials VV and RR of the last two steps of the remainder sequence.

Initialise B with an empty sequence modulo the prime pp, and free it.

Empty the sequence of B; the second function also changes the prime to pp.

Append count reduced points, count zeros, or one point to the sequence. The polynomials are updated only by nmod_berlekamp_massey_reduce.

Brings VV and RR up to date with all points added and returns 1 if VV changed, 0 otherwise.

More

Return the number of points added and a pointer to them (which may be NULL if there are none).

Prints VV in pretty format with variable #, a comma and the points.

Bit packing#

These functions convert between polynomials and integers by placing the coefficients in fixed-width bit fields, that is, by evaluating at 2bits2^{\mathit{bits}}. They are the building blocks of Kronecker substitution.

Writes ∑ipolyi2i⋅bits\sum_i \mathit{poly}_i 2^{i \cdot \mathit{bits}} to res as ⌈len⋅bits/FLINT_BITS⌉\lceil \mathit{len} \cdot \mathit{bits} / \mathtt{FLINT\_BITS} \rceil limbs. Requires len≥1\mathit{len} \ge 1, 1≤bits<3FLINT_BITS1 \le \mathit{bits} < 3 \mathtt{FLINT\_BITS} and every coefficient less than 2bits2^{\mathit{bits}}.

Reads the bit fields nlo,…,nhi−1\mathit{nlo}, \ldots, \mathit{nhi} - 1 of width bits from mpn, reduces them modulo nn and writes them to res[0], ..., res[nhi - nlo - 1]. The fields may hold any value. Requires 1≤bits<3FLINT_BITS1 \le \mathit{bits} < 3 \mathtt{FLINT\_BITS}.

void nmod_poly_bit_pack(fmpz_t f, const nmod_poly_t poly, flint_bitcnt_t bit_size)

Sets f=poly(2bit_size)f = \mathit{poly}(2^{\mathit{bit\_size}}). Every coefficient must be less than 2bit_size2^{\mathit{bit\_size}}; 1≤bit_size<3FLINT_BITS1 \le \mathit{bit\_size} < 3 \mathtt{FLINT\_BITS}. For bit_size = 0 or the zero polynomial, f=0f = 0.

Sets poly to the polynomial whose coefficients are the bit fields of width bit_size of f≥0f \ge 0, reduced modulo nn; the inverse of nmod_poly_bit_pack for reduced coefficients. Throws FLINT_ERROR for f<0f < 0. For bit_size = 0 the result is 0.

Write kk zero bits followed by the nn values op[0], op[s], ..., op[(n-1) s] in fields of bb bits to res, and zero-pad the output to rr limbs if r≠0r \ne 0. Each value must be less than 2b2^b. The pack1 version requires b≤FLINT_BITSb \le \mathtt{FLINT\_BITS}, the other b≤3FLINT_BITSb \le 3 \mathtt{FLINT\_BITS}. Used by _nmod_poly_mul_KS2 and _nmod_poly_mul_KS4.

Skip kk bits of op and extract nn fields of bb bits, writing each as one, two or three words to res. _nmod_poly_KS2_unpack1 requires b≤FLINT_BITSb \le \mathtt{FLINT\_BITS}, unpack2 FLINT_BITS<b≤2FLINT_BITS\mathtt{FLINT\_BITS} < b \le 2 \mathtt{FLINT\_BITS}, unpack3 2FLINT_BITS<b<3FLINT_BITS2 \mathtt{FLINT\_BITS} < b < 3 \mathtt{FLINT\_BITS}; _nmod_poly_KS2_unpack dispatches on bb.

Reduces nn values of w∈{1,2,3}w \in \{1, 2, 3\} words each, stored consecutively in op, modulo nn, writing them to res[0], res[s], ... with stride ss.

Recover nn coefficients of 2b2b bits from two sequences of n+1n + 1 digits of bb bits, unpacked from an integer product evaluated at 2b2^b (op1, low digits first) and from the product of the reversed polynomials (op2), propagating the borrows between them; reduce the coefficients modulo nn and write them with stride ss. Used by _nmod_poly_mul_KS4. The variants require 2b≤FLINT_BITS2b \le \mathtt{FLINT\_BITS} (1), FLINT_BITS<2b<2FLINT_BITS\mathtt{FLINT\_BITS} < 2b < 2 \mathtt{FLINT\_BITS} (2), b=FLINT_BITSb = \mathtt{FLINT\_BITS} (2b) and 2FLINT_BITS<2b≤3FLINT_BITS2 \mathtt{FLINT\_BITS} < 2b \le 3 \mathtt{FLINT\_BITS} (3); the version without suffix dispatches on bb.

Internal functions#

The following helpers are declared in the header for use by other modules and by the functions above.

_nmod_poly_divrem_basecase given invB =lc⁡(B)−1= \operatorname{lc}(B)^{-1}. Same conventions; RR may be the same array as AA.

Division with remainder for lenA=lenB+1\mathit{lenA} = \mathit{lenB} + 1, the typical step of the Euclidean algorithm, given invL =lc⁡(B)−1= \operatorname{lc}(B)^{-1}. Writes two coefficients to QQ and lenB−1\mathit{lenB} - 1 to RR. RR may be the same array as AA, but QQ must not overlap AA. The two quotient coefficients are computed first, and each remainder coefficient ai−q1bi−1−q0bia_i - q_1 b_{i-1} - q_0 b_i is then formed with a single reduction, using Lemire, Barrett or Möller–Granlund reduction depending on the size of nn.

Bookkeeping for the resultant in a half-GCD computation (the resultant so far, the last leading coefficient and lengths). No function of the library uses it: the half-GCD functions above use the generic implementation in gr_poly.

An argument structure for computing the matrix of nmod_poly_precompute_matrix in a thread. It is not used by the library.

References#

  • [Har2009a] D. Harvey, "Faster polynomial multiplication via multipoint Kronecker substitution", Journal of Symbolic Computation 44:10 (2009), 1502–1510
  • [Sho1995] V. Shoup, "A new polynomial factorization algorithm and its implementation", Journal of Symbolic Computation 20:4 (1995), 363–397
  • [ThullYap1990] Thull, K. and Yap, C. : A Unified Approach to HGCD Algorithms for Polynomials and Integers, (1990)
  • [PS1973] M. S. Paterson and L. J. Stockmeyer, "On the number of nonscalar multiplications necessary to evaluate polynomials", SIAM J. Comput (1973)
  • [Blu1970] L. I. Bluestein. A linear filtering approach to the computation of discrete Fourier transform. IEEE Transactions on Audio and Electroacoustics 18:4 (1970), 451–455. https://doi.org/10.1109/TAU.1970.1162132
  • [RSR1969] L. R. Rabiner, R. W. Schafer and C. M. Rader. The chirp z-transform algorithm. IEEE Transactions on Audio and Electroacoustics 17:2 (1969), 86–92. https://doi.org/10.1109/TAU.1969.1162034
  • [BS2005] A. Bostan and É. Schost. Polynomial evaluation and interpolation on special sets of points. Journal of Complexity 21 (2005), 420–446.
  • [ASU1975] A. V. Aho, K. Steiglitz and J. D. Ullman. Evaluating polynomials at fixed sets of points. SIAM Journal on Computing 4 (1975), 533–539.
  • [GG1997] J. von zur Gathen and J. Gerhard. Fast algorithms for Taylor shifts and certain difference equations. ISSAC 1997, 40–47.
  • [BrentKung1978] Brent, R. P. and Kung, H. T. : Fast Algorithms for Manipulating Formal Power Series, J. ACM 25:4 (1978) 581–595
  • [GatSho1992] J. von zur Gathen and V. Shoup, "Computing Frobenius maps and factoring polynomials", Computational Complexity 2 (1992), 187-224. https://doi.org/10.1007/BF01272074
  • [KalSho1998] E. Kaltofen and V. Shoup, "Subquadratic-time factoring of polynomials over finite fields", Mathematics of Computation 67 (1998), 1179-1197. https://doi.org/10.1090/S0025-5718-98-00944-2
  • [Sch1982b] A. Schönhage. The fundamental theorem of algebra in terms of computational complexity. Technical report, Universität Tübingen, 1982.
  • [BFSS2006] A. Bostan, P. Flajolet, B. Salvy and É. Schost. "Fast computation of special resultants". Journal of Symbolic Computation, 41(1):1–29, January 2006. https://doi.org/10.1016/j.jsc.2005.07.001
  • [HZ2004] G. Hanrot and P. Zimmermann, "Newton Iteration Revisited" (2004), http://www.loria.fr/~zimmerma/papers/fastnewton.ps.gz
  • [BZ2011] R. P. Brent and P. Zimmermann, Modern Computer Arithmetic, Cambridge University Press (2011), http://www.loria.fr/~zimmerma/mca/pub226.html
  • [Lüb2004] F. Lübeck, "Conway polynomials for finite fields", RTWH Aachen, https://www.math.rwth-aachen.de/~Frank.Luebeck/data/ConwayPol/index.html, (accessed 2024-01-12)
  • [Ber1968] E. R. Berlekamp. Algebraic Coding Theory. McGraw-Hill, 1968.
  • [Mas1969] J. L. Massey. Shift-register synthesis and BCH decoding. IEEE Transactions on Information Theory 15 (1969), 122–127.
  • [SKHN1975] Y. Sugiyama, M. Kasahara, S. Hirasawa and T. Namekawa. A method for solving key equation for decoding Goppa codes. Information and Control 27 (1975), 87–99.
Cite this page

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