nmod_poly.h
#include <flint/nmod_poly.h>This module implements dense univariate polynomials over for a word-size modulus . A polynomial is an nmod_poly_t: an array of ulong coefficients reduced modulo , 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 costs word operations for large . 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/nZHownmod_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 . The structure has the fields coeffs (an array of alloc coefficients), alloc, length and mod (an nmod_t for , see nmod.h). An nmod_poly_t is an array of one nmod_poly_struct, so it is passed by reference. The coefficient of 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 . Coefficients are reduced, that is, lie in . 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 annmod_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 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_IMPINVorFLINT_ERROR), but a composite modulus can also give wrong results without warning. The GCD and resultant functions always throwFLINT_IMPINVwhen 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#
void nmod_poly_init(nmod_poly_t poly, ulong n)void nmod_poly_init_preinv(nmod_poly_t poly, ulong n, ulong ninv)Initialise poly as the zero polynomial modulo , 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)void nmod_poly_init2_preinv(nmod_poly_t poly, ulong n, ulong ninv, slong alloc)Like nmod_poly_init and nmod_poly_init_preinv, but allocate space for alloc coefficients.
void nmod_poly_realloc(nmod_poly_t poly, slong alloc)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.
void nmod_poly_fit_length(nmod_poly_t poly, slong alloc)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.
void nmod_poly_clear(nmod_poly_t poly)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.
void _nmod_poly_set_length(nmod_poly_t poly, slong len)Sets the length field of poly to len without zeroing or normalising anything. poly must have space for len coefficients.
void _nmod_poly_normalise(nmod_poly_t poly)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#
slong nmod_poly_length(const nmod_poly_t poly)slong nmod_poly_degree(const nmod_poly_t poly)Return the length and the degree of poly. The zero polynomial has length 0 and degree .
ulong nmod_poly_modulus(const nmod_poly_t poly)Returns the modulus of poly.
flint_bitcnt_t nmod_poly_max_bits(const nmod_poly_t poly)Returns the number of bits of the largest coefficient of poly, or 0 for the zero polynomial.
nn_ptr nmod_poly_lead(const nmod_poly_t poly)Returns a pointer to the leading coefficient of poly, or NULL if poly is zero.
slong _nmod_poly_hamming_weight(nn_srcptr a, slong len)slong nmod_poly_hamming_weight(const nmod_poly_t A)Return the number of nonzero coefficients.
int nmod_poly_is_zero(const nmod_poly_t poly)Returns whether poly is the zero polynomial.
int nmod_poly_is_one(const nmod_poly_t poly)int nmod_poly_is_gen(const nmod_poly_t poly)Return whether poly is the constant 1, respectively the generator . For both return 1, since every polynomial is zero modulo 1.
int nmod_poly_is_unit(const nmod_poly_t poly)Returns whether poly is a nonzero constant, which for prime is the same as being a unit. For composite the result does not tell whether the constant is invertible. For it returns 1.
int nmod_poly_is_monic(const nmod_poly_t poly)Returns whether poly is nonzero with leading coefficient 1.
Assignment and coefficients#
void nmod_poly_set(nmod_poly_t a, const nmod_poly_t b)Sets a to a copy of b.
void nmod_poly_swap(nmod_poly_t poly1, nmod_poly_t poly2)Swaps poly1 and poly2 in constant time by swapping the structures, including the moduli.
void nmod_poly_zero(nmod_poly_t res)void nmod_poly_one(nmod_poly_t res)Set res to 0 and to 1. Modulo , nmod_poly_one sets res to the zero polynomial.
void nmod_poly_set_trunc(nmod_poly_t res, const nmod_poly_t poly, slong len)void nmod_poly_truncate(nmod_poly_t poly, slong len)Set res to poly truncated to length len, that is, poly modulo , 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 of the input viewed as a polynomial of length : coefficient of the output is coefficient of the input, taken as 0 beyond its length. Input coefficients from index on are ignored.
ulong nmod_poly_get_coeff_ui(const nmod_poly_t poly, slong j)Returns the coefficient of , or 0 if is at least the length. Requires .
void nmod_poly_set_coeff_ui(nmod_poly_t poly, slong j, ulong c)Sets the coefficient of to , for any . The polynomial grows, with zero coefficients in between, or shrinks if the leading coefficient is set to zero.
Comparison#
int nmod_poly_equal(const nmod_poly_t a, const nmod_poly_t b)Returns whether a and b are equal. The moduli are not compared.
int nmod_poly_equal_nmod(const nmod_poly_t poly, ulong cst)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 . A negative is treated as 0.
Random polynomials#
The rand functions draw coefficients uniformly from . 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.
void nmod_poly_rand(nmod_poly_t poly, flint_rand_t state, slong len)void nmod_poly_rand_monic(nmod_poly_t poly, flint_rand_t state, slong len)Set poly to a random polynomial of length at most len, respectively a random monic polynomial of length exactly .
void nmod_poly_rand_irreducible(nmod_poly_t poly, flint_rand_t state, slong len)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.
void nmod_poly_randtest(nmod_poly_t poly, flint_rand_t state, slong len)void nmod_poly_randtest_not_zero(nmod_poly_t poly, flint_rand_t state, slong len)void nmod_poly_randtest_monic(nmod_poly_t poly, flint_rand_t state, slong len)Set poly to a random test polynomial of length at most len, a nonzero one (requires and ), and a monic one of length exactly .
void nmod_poly_randtest_irreducible(nmod_poly_t poly, flint_rand_t state, slong len)void nmod_poly_randtest_monic_irreducible(nmod_poly_t poly, flint_rand_t state, slong len)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 .
void nmod_poly_randtest_monic_primitive(nmod_poly_t poly, flint_rand_t state, slong len)Sets poly to a random monic irreducible polynomial of length whose root generates the multiplicative group of the field . Primitivity is tested with fq_nmod_is_primitive.
void nmod_poly_randtest_trinomial(nmod_poly_t poly, flint_rand_t state, slong len)void nmod_poly_randtest_pentomial(nmod_poly_t poly, flint_rand_t state, slong len)Set poly to a random monic polynomial of length len with at most three nonzero terms , (requires ), respectively at most five nonzero terms (requires ).
int nmod_poly_randtest_trinomial_irreducible(nmod_poly_t poly, flint_rand_t state, slong len, slong max_attempts)int nmod_poly_randtest_pentomial_irreducible(nmod_poly_t poly, flint_rand_t state, slong len, slong max_attempts)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.
void nmod_poly_randtest_sparse_irreducible(nmod_poly_t poly, flint_rand_t state, slong len)Sets poly to a sparse monic irreducible polynomial of length len: it tries trinomials, then 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 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_print(const nmod_poly_t a)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_read(nmod_poly_t poly)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#
void _nmod_poly_shift_left(nn_ptr res, nn_srcptr poly, slong len, slong k)void nmod_poly_shift_left(nmod_poly_t res, const nmod_poly_t poly, slong k)Set res to poly times , for . The underscore version writes coefficients and allows res == poly.
void _nmod_poly_shift_right(nn_ptr res, nn_srcptr poly, slong len, slong k)void nmod_poly_shift_right(nmod_poly_t res, const nmod_poly_t poly, slong k)Set res to poly divided by , discarding the remainder, for . In the underscore version len is the length of the output: it sets res[i] = poly[i + k] for , so poly must have at least 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 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 , and .
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 . A negative is treated as 0.
void nmod_poly_add_ui(nmod_poly_t res, const nmod_poly_t poly, ulong c)void nmod_poly_sub_ui(nmod_poly_t res, const nmod_poly_t poly, ulong c)Set res to and , for any .
Scalar multiplication#
void nmod_poly_scalar_mul_nmod(nmod_poly_t res, const nmod_poly_t poly, ulong c)Sets res to , for reduced . The result is normalised, which matters for composite .
void nmod_poly_scalar_addmul_nmod(nmod_poly_t res, const nmod_poly_t poly, ulong c)Sets res to , for reduced .
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 (otherwise FLINT_IMPINV is thrown). nmod_poly_make_monic throws FLINT_DIVZERO for the zero polynomial; the underscore version requires 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 :
- 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 withflint_mpn_mul, and its multipoint variantsKS2andKS4[Har2009a], for medium lengths; - the small-prime FFT of
fft_smallfor long operands, when FLINT is built with it (the usual case on x86-64 and ARM64). Moduli use a repacked product of half the length.
The crossover points, tabulated for each bit size of , 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).
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 . The underscore version requires , writes coefficients and does not allow res to overlap the inputs; poly1 == poly2 (squaring) is allowed and faster.
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, . The underscore version requires and , writes trunc coefficients and does not allow aliasing. Inputs longer than trunc are allowed.
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 on to those of the product. The coefficients below are either zero or the coefficients of the product. The underscore version requires , writes coefficients and does not allow aliasing.
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 of the product, that is, . The underscore version requires in either order and , writes coefficients and does not allow aliasing. The non-underscore version accepts any .
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 operations. The underscore version requires and does not allow aliasing.
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 by the classical algorithm. The underscore version requires and , 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 , writes 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 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 , with large enough that the coefficients of the product do not overlap, multiplies the resulting integers and reads off the coefficients. KS2 evaluates at and and KS4 also at and , 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.
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 in either order.
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 by Kronecker substitution. The underscore version requires and . It multiplies the operands truncated to length in full and unpacks the low 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 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(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)void nmod_poly_mul_KS4(nmod_poly_t res, const nmod_poly_t poly1, const nmod_poly_t poly2)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 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.
void _nmod_poly_mulmid_fft_small(nn_ptr z, nn_srcptr a, slong an, nn_srcptr b, slong bn, slong znlo, slong zn, nmod_t mod)void _nmod_poly_mullow_fft_small(nn_ptr z, nn_srcptr a, slong an, nn_srcptr b, slong bn, slong zn, nmod_t mod)Write the coefficients (respectively ) of the product of (a, an) and (b, bn) to z, using fft_small. Require , in either order, and ; the output must not overlap the inputs.
int _nmod_poly_mullow_want_fft_small(slong len1, slong len2, slong n, int squaring, nmod_t mod)int _nmod_poly_mulmid_want_fft_small(slong len2, slong m, 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 (a full product if ), respectively for coefficients of a middle product whose shorter operand, after trimming, has length len2.
int _nmod_poly_mulmid_fft_small_repack(nn_ptr z, nn_srcptr a, slong an, nn_srcptr b, slong bn, slong znlo, slong zn, nmod_t mod)Internal helper of _nmod_poly_mulmid_fft_small for : if the coefficients are small enough, writes the coefficients 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.
Powering#
void nmod_poly_pow(nmod_poly_t res, const nmod_poly_t poly, ulong e)void nmod_poly_pow_binexp(nmod_poly_t res, const nmod_poly_t poly, ulong e)Set res to by binary exponentiation; the two pairs of functions are the same. The underscore versions require and , write coefficients and do not allow aliasing. nmod_poly_pow returns 1 for , but nmod_poly_pow_binexp returns 0.
void nmod_poly_pow_trunc(nmod_poly_t res, const nmod_poly_t poly, ulong e, slong trunc)void nmod_poly_pow_trunc_binexp(nmod_poly_t res, const nmod_poly_t poly, ulong e, slong trunc)Set res to 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 and , write trunc coefficients and do not allow aliasing.
Division#
Division with remainder by requires the leading coefficient of to be invertible modulo ; otherwise FLINT_IMPINV is thrown. Division by the zero polynomial throws FLINT_DIVZERO, except modulo , where nmod_poly_divrem, nmod_poly_div and nmod_poly_divexact return and . 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.
nmod_poly.
void _nmod_poly_divrem(nn_ptr Q, nn_ptr R, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)void nmod_poly_divrem(nmod_poly_t Q, nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B)Set and to the quotient and remainder of by , so that with . The underscore version requires and writes coefficients to and to . may be the same array as ; otherwise the outputs must not overlap each other or the inputs.
Full documentationvoid nmod_poly_div(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)Set to the quotient of by without computing the remainder. The underscore version requires , writes coefficients and does not allow aliasing.
Full documentationvoid nmod_poly_rem(nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B)Set to the remainder of by . The underscore version requires , writes 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 even modulo 1.
void nmod_poly_divexact(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)Set to , assuming that divides ; otherwise the result is meaningless. The underscore version requires , writes coefficients and does not allow aliasing.
Full documentationulong nmod_poly_div_root(nmod_poly_t Q, const nmod_poly_t A, ulong c)Set to the quotient of by and return the remainder , by Horner's rule (synthetic division). The value must be reduced. The underscore version requires (for smaller lengths it returns 0 and writes nothing), writes coefficients and allows Q == A.
int nmod_poly_divides(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)int _nmod_poly_divides_classical(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)int nmod_poly_divides_classical(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)If divides , set and return 1; otherwise set and return 0. The zero polynomial divides only itself. The underscore versions require , write coefficients and do not allow aliasing.
Full documentationulong nmod_poly_remove(nmod_poly_t f, const nmod_poly_t p)Removes the largest power dividing f from f and returns . Requires : for a nonzero constant the function does not terminate. For it returns 0.
void _nmod_poly_divrem_basecase(nn_ptr Q, nn_ptr R, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)void nmod_poly_divrem_basecase(nmod_poly_t Q, nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B)Division with remainder by the schoolbook algorithm, with the same conventions as _nmod_poly_divrem and nmod_poly_divrem.
void _nmod_poly_div_newton_n_preinv(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nn_srcptr Binv, slong lenBinv, nmod_t mod)void nmod_poly_div_newton_n_preinv(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B, const nmod_poly_t Binv)Set to the quotient of by , given the power series inverse Binv of the reversal of (see Computing modulo a fixed polynomial). The quotient is the reversal of , so Binv must be correct modulo , . The underscore version requires , does not read , and does not allow to overlap Binv.
void _nmod_poly_divrem_newton_n_preinv(nn_ptr Q, nn_ptr R, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nn_srcptr Binv, slong lenBinv, nmod_t mod)void nmod_poly_divrem_newton_n_preinv(nmod_poly_t Q, nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B, const nmod_poly_t Binv)Set and to the quotient and remainder of by , given Binv as for nmod_poly_div_newton_n_preinv; the remainder is computed by a short product. The underscore version requires and does not allow the outputs to overlap the inputs.
Power series inversion and division#
These functions compute with power series truncated to length , that is, modulo . The constant term of the divisor must be invertible modulo ; otherwise FLINT_IMPINV is thrown. For long series they use Newton iteration, which costs a small constant number of multiplications of length . See Power series inversion and division.
void nmod_poly_inv_series(nmod_poly_t Qinv, const nmod_poly_t Q, slong n)Set Qinv to the inverse of the power series modulo , that is, . The underscore version requires and , writes coefficients and does not allow aliasing; may be longer than . The non-underscore version throws FLINT_DIVZERO if or .
void nmod_poly_inv_series_basecase(nmod_poly_t Qinv, const nmod_poly_t Q, slong n)The same, by the recurrence , , with each sum computed as a dot product. A binomial is inverted directly as a geometric series.
Full documentationvoid nmod_poly_inv_series_newton(nmod_poly_t Qinv, const nmod_poly_t Q, slong n)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.
void _nmod_poly_div_series(nn_ptr Q, nn_srcptr A, slong Alen, nn_srcptr B, slong Blen, slong n, nmod_t mod)void nmod_poly_div_series(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B, slong n)Set to , so that . The underscore version requires , writes coefficients and does not allow aliasing. The non-underscore version throws FLINT_DIVZERO if , or .
void _nmod_poly_div_series_basecase(nn_ptr Q, nn_srcptr A, slong Alen, nn_srcptr B, slong Blen, slong n, nmod_t mod)void nmod_poly_div_series_basecase(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B, slong n)The same by the recurrence .
Full documentationArithmetic modulo a polynomial#
These functions compute in for a nonzero whose leading coefficient is invertible. Elements are represented by their remainders, polynomials of length less than ; the underscore functions usually require them to be zero-padded to length exactly . The _preinv variants take the power series inverse finv of the reversal of , 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 , computed as a product followed by _nmod_poly_divrem. The underscore version requires and (otherwise there is nothing to reduce; use _nmod_poly_mul), writes coefficients and does not allow res to overlap . The non-underscore version accepts inputs of any length and throws FLINT_ERROR for .
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 , reducing with _nmod_poly_divrem_newton_n_preinv and the precomputed finv. Both factors must be reduced modulo : the non-underscore version throws FLINT_ERROR if or . The underscore version also requires and , writes coefficients and does not allow res to overlap or finv.
int _nmod_poly_invmod(ulong * A, const ulong * B, slong lenB, const ulong * P, slong lenP, const nmod_t mod)int nmod_poly_invmod(nmod_poly_t A, const nmod_poly_t B, const nmod_poly_t P)If is invertible modulo , set to its inverse and return 1; otherwise return 0, leaving undefined. Requires a prime modulus. The non-underscore version reduces modulo first, returns 0 for and throws FLINT_ERROR if . The underscore version requires (zero padding of is allowed), writes coefficients and does not allow aliasing. It calls the extended Euclidean algorithm _nmod_poly_gcdinv.
void _nmod_poly_powmod_ui_binexp(nn_ptr res, nn_srcptr poly, ulong e, nn_srcptr f, slong lenf, nmod_t mod)void nmod_poly_powmod_ui_binexp(nmod_poly_t res, const nmod_poly_t poly, ulong e, const nmod_poly_t f)void _nmod_poly_powmod_fmpz_binexp(nn_ptr res, nn_srcptr poly, fmpz_t e, nn_srcptr f, slong lenf, nmod_t mod)void nmod_poly_powmod_fmpz_binexp(nmod_poly_t res, const nmod_poly_t poly, fmpz_t e, const nmod_poly_t f)Set res to by left-to-right binary exponentiation, reducing each product with _nmod_poly_divrem. The non-underscore versions accept any poly (reducing it first) and , and throw FLINT_ERROR for . The underscore versions require , poly reduced and zero-padded to length , and ; they write coefficients and do not allow aliasing.
void _nmod_poly_powmod_ui_binexp_preinv(nn_ptr res, nn_srcptr poly, ulong e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)void nmod_poly_powmod_ui_binexp_preinv(nmod_poly_t res, const nmod_poly_t poly, ulong e, const nmod_poly_t f, const nmod_poly_t finv)void _nmod_poly_powmod_fmpz_binexp_preinv(nn_ptr res, nn_srcptr poly, fmpz_t e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)void nmod_poly_powmod_fmpz_binexp_preinv(nmod_poly_t res, const nmod_poly_t poly, fmpz_t e, const nmod_poly_t f, const nmod_poly_t finv)The same with a precomputed finv, reducing with _nmod_poly_divrem_newton_n_preinv. These are the functions to use for large or many exponentiations modulo the same .
void _nmod_poly_powmod_x_ui_preinv(nn_ptr res, ulong e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)void nmod_poly_powmod_x_ui_preinv(nmod_poly_t res, ulong e, const nmod_poly_t f, const nmod_poly_t finv)void _nmod_poly_powmod_x_fmpz_preinv(nn_ptr res, fmpz_t e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)void nmod_poly_powmod_x_fmpz_preinv(nmod_poly_t res, fmpz_t e, const nmod_poly_t f, const nmod_poly_t finv)Set res to , given finv. They use sliding-window exponentiation in which a multiplication by is a shift followed by a reduction, so each window costs one reduction instead of a full multiplication. The underscore versions require and and write coefficients; the non-underscore versions accept and any nonzero .
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)void nmod_poly_powers_mod_naive(nmod_poly_struct * res, const nmod_poly_t f, slong n, const nmod_poly_t g)Set res[i] to for , computing as . The non-underscore version takes an array of initialised polynomials, reduces first, and throws FLINT_ERROR for ; for or constant it sets res[0] to 1 and the others to 0. The underscore version requires , ginv as for _nmod_poly_mulmod_preinv, and arrays of 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)void nmod_poly_powers_mod_bsgs(nmod_poly_struct * res, const nmod_poly_t f, slong n, const nmod_poly_t g)The same as the naive functions, computed with baby steps and giant steps in parallel: with , the powers and are computed first, and then the threads fill in , taking blocks of 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 are needed with the same and , data depending on can be precomputed so that each product is cheaper than nmod_poly_mulmod_preinv. Two methods are available. The matrix method stores the matrix of multiplication by , whose column is , , and computes as a matrix-vector product; for small moduli several entries are packed into one word. It costs but is very fast for up to a few hundred. The Shoup method stores the quotient ; then the quotient of by is the high part of a short product, and costs three short products instead of four, by the polynomial analogue of Shoup multiplication [Sho1995].
Precomputed data for multiplication by a fixed modulo a fixed . It stores shallow references to , and the inverse of , 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.
void _nmod_poly_mulmod_precond_init_method(nmod_poly_mulmod_precond_t precond, nn_srcptr a, slong alen, nn_srcptr d, slong dlen, nn_srcptr dinv, slong lendinv, int method, nmod_t mod)void nmod_poly_mulmod_precond_init_method(nmod_poly_mulmod_precond_t precond, const nmod_poly_t a, const nmod_poly_t d, const nmod_poly_t dinv, int method)Initialise precond for multiplication by modulo with the given method. Require reduced modulo () and dinv the power series inverse of the reversal of , as for nmod_poly_mulmod_preinv; the matrix method only reads dinv[0]. An invalid method throws FLINT_ERROR.
void _nmod_poly_mulmod_precond_init_num(nmod_poly_mulmod_precond_t precond, nn_srcptr a, slong alen, nn_srcptr d, slong dlen, nn_srcptr dinv, slong lendinv, slong num, nmod_t mod)void nmod_poly_mulmod_precond_init_num(nmod_poly_mulmod_precond_t precond, const nmod_poly_t a, const nmod_poly_t d, const nmod_poly_t dinv, slong num)Like the init_method functions, but choose the method expected to be fastest for num multiplications.
void nmod_poly_mulmod_precond_clear(nmod_poly_mulmod_precond_t precond)Frees the memory used by precond.
void _nmod_poly_mulmod_precond(nn_ptr res, const nmod_poly_mulmod_precond_t precond, nn_srcptr b, slong blen, nmod_t mod)void nmod_poly_mulmod_precond(nmod_poly_t res, const nmod_poly_mulmod_precond_t precond, const nmod_poly_t b)Set res to for the and of precond. Require reduced modulo . The underscore version requires , writes coefficients (zero-padded) and does not allow res to overlap , or . The non-underscore version allows res to be , but not .
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 , and accept their inputs in any order. Below a cutoff that depends on the bit size of the Euclidean algorithm is used, for moduli of to bits and in Montgomery arithmetic; above it the half-GCD algorithm [ThullYap1990] computes the GCD in operations. See Greatest common divisors.
nmod_poly.
void nmod_poly_gcd(nmod_poly_t G, const nmod_poly_t A, const nmod_poly_t B)Set to a greatest common divisor of and . The underscore version requires , writes at most coefficients, returns the length of , does not make monic and does not allow aliasing.
Full documentationslong _nmod_poly_gcd_euclidean(nn_ptr G, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)void nmod_poly_gcd_euclidean(nmod_poly_t G, const nmod_poly_t A, const nmod_poly_t B)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 .
slong _nmod_poly_gcd_euclidean_redc_fast(nn_ptr G, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)void nmod_poly_gcd_euclidean_redc_fast(nmod_poly_t G, const nmod_poly_t A, const nmod_poly_t B)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 , which is not checked.
NMOD_POLY_GCD_EUCLIDEAN_USE_REDC_FAST(lenB, mod)The condition under which _nmod_poly_gcd and _nmod_poly_resultant use the Montgomery version of the Euclidean algorithm: and NMOD_BITS(mod) . It does not check that 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.
void nmod_poly_gcd_hgcd(nmod_poly_t G, const nmod_poly_t A, const nmod_poly_t B)The GCD by the half-GCD algorithm, with the conventions of _nmod_poly_gcd and nmod_poly_gcd. Its complexity is , where is the cost of a multiplication of length .
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)slong nmod_poly_hgcd(nmod_poly_t m11, nmod_poly_t m12, nmod_poly_t m21, nmod_poly_t m22, nmod_poly_t A, nmod_poly_t B, const nmod_poly_t a, const nmod_poly_t b)The half-GCD step. For , compute consecutive remainders of the Euclidean remainder sequence of with and the matrix
the product of the matrices for the quotients of these steps. Return .
Full documentationslong nmod_poly_hgcd_ref(nmod_poly_t m11, nmod_poly_t m12, nmod_poly_t m21, nmod_poly_t m22, nmod_poly_t A, nmod_poly_t B, const nmod_poly_t a, const nmod_poly_t b)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 from which _nmod_poly_gcd (470 to 2199) and _nmod_poly_xgcd (72 to 388) use the half-GCD algorithm.
slong _nmod_poly_xgcd(nn_ptr G, nn_ptr S, nn_ptr T, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)void nmod_poly_xgcd(nmod_poly_t G, nmod_poly_t S, nmod_poly_t T, const nmod_poly_t A, const nmod_poly_t B)Compute the GCD of and and cofactors with . The non-underscore version makes monic; for the cofactors satisfy and , and for it returns , . , and must be distinct objects.
Full documentationslong _nmod_poly_xgcd_euclidean(nn_ptr res, nn_ptr s, nn_ptr t, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)void nmod_poly_xgcd_euclidean(nmod_poly_t G, nmod_poly_t S, nmod_poly_t T, const nmod_poly_t A, const nmod_poly_t B)slong _nmod_poly_xgcd_hgcd(nn_ptr G, nn_ptr S, nn_ptr T, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)void nmod_poly_xgcd_hgcd(nmod_poly_t G, nmod_poly_t S, nmod_poly_t T, const nmod_poly_t A, const nmod_poly_t B)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)void nmod_poly_gcdinv(nmod_poly_t G, nmod_poly_t S, const nmod_poly_t A, const nmod_poly_t B)Compute and with and , without the cofactor of . If , then . The non-underscore version requires (otherwise it throws FLINT_ERROR), reduces modulo first, makes monic and returns if divides . The underscore version requires , writes at most lenA coefficients to and to , returns the length of and does not make monic.
Resultant and discriminant#
The resultant of and is
the determinant of the Sylvester matrix. It is zero exactly when and have a common factor. These functions require a prime modulus (not checked) and return 0 if either polynomial is zero. See Resultants and discriminants.
ulong nmod_poly_resultant(const nmod_poly_t f, const nmod_poly_t g)Return . The underscore version requires .
Full documentationulong _nmod_poly_resultant_euclidean(nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)ulong nmod_poly_resultant_euclidean(const nmod_poly_t f, const nmod_poly_t g)The resultant by the Euclidean algorithm, using for .
Full documentationulong nmod_poly_resultant_hgcd(const nmod_poly_t A, const nmod_poly_t B)The resultant by the half-GCD algorithm, in operations.
Full documentationulong _nmod_poly_discriminant(nn_srcptr poly, slong len, nmod_t mod)ulong nmod_poly_discriminant(const nmod_poly_t f)Return the discriminant of of degree ,
where the power of is adjusted if (when the characteristic divides ). The discriminant is 0 for constants and when . The underscore version requires .
Full documentationDerivative and integral#
void _nmod_poly_derivative(nn_ptr x_prime, nn_srcptr x, slong len, nmod_t mod)void nmod_poly_derivative(nmod_poly_t x_prime, const nmod_poly_t x)Set x_prime to the derivative of x. The underscore version requires , writes coefficients and allows x_prime == x.
void _nmod_poly_integral(nn_ptr x_int, nn_srcptr x, slong len, nmod_t mod)void nmod_poly_integral(nmod_poly_t x_int, const nmod_poly_t x)Set x_int to the integral of x with constant term 0. The integers must be invertible modulo , for example prime and ; otherwise FLINT_IMPINV is thrown. Here len is the length of the output: the underscore version reads coefficients, writes len coefficients, requires and allows x_int == x. It needs only one modular inversion.
Evaluation#
ulong nmod_poly_evaluate_nmod(const nmod_poly_t poly, ulong c)Return for reduced . Any length, including 0, is allowed.
MoreReturn by Horner's rule, and by rectangular splitting: with , the powers are computed once, each block of coefficients is evaluated by a dot product (see Computing dot products), and the blocks are combined by Horner's rule in . 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.
ulong _nmod_poly_evaluate_nmod_precomp(nn_srcptr poly, slong len, ulong c, ulong c_precomp, ulong modn)ulong _nmod_poly_evaluate_nmod_precomp_lazy(nn_srcptr poly, slong len, ulong c, ulong c_precomp, ulong modn)Evaluate poly at modulo modn by Horner's rule with Shoup multiplication, given c_precomp = n_mulmod_precomp_shoup(c, modn). Require .
void nmod_poly_evaluate_mat(nmod_mat_t dest, const nmod_poly_t poly, const nmod_mat_t c)void nmod_poly_evaluate_mat_horner(nmod_mat_t dest, const nmod_poly_t poly, const nmod_mat_t c)void nmod_poly_evaluate_mat_paterson_stockmeyer(nmod_mat_t dest, const nmod_poly_t poly, const nmod_mat_t c)Set dest to the matrix , for a square matrix with the modulus of poly; dest must have the same dimensions and may be c. The Horner version uses matrix multiplications, the Paterson–Stockmeyer version [PS1973] about matrix multiplications and scalar multiply-adds. nmod_poly_evaluate_mat uses Horner's rule if or for an matrix, and Paterson–Stockmeyer otherwise.
void nmod_mat_one_addmul(nmod_mat_t dest, const nmod_mat_t mat, ulong c)Sets dest to for a square matrix mat and reduced , the step of Horner's rule above. dest may be mat.
Multipoint evaluation and interpolation#
Evaluating a polynomial of length at points, or interpolating through points, takes operations with Horner's rule or Lagrange interpolation, and operations with a subproduct tree: the products 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 to be distinct, with invertible differences (for example, prime). See Multipoint evaluation and interpolation.
AlgorithmMultipoint evaluation and interpolationEvaluation of a polynomial at many points and interpolation through many points in 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.void _nmod_poly_evaluate_nmod_vec(nn_ptr ys, nn_srcptr coeffs, slong ilen, nn_srcptr xs, slong olen, nmod_t mod)void nmod_poly_evaluate_nmod_vec(nn_ptr ys, const nmod_poly_t poly, nn_srcptr xs, slong olen)Set ys[i] to for , 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.
void _nmod_poly_evaluate_nmod_vec_iter(nn_ptr ys, nn_srcptr coeffs, slong ilen, nn_srcptr xs, slong olen, nmod_t mod)void nmod_poly_evaluate_nmod_vec_iter(nn_ptr ys, const nmod_poly_t poly, nn_srcptr xs, slong olen)The same, evaluating at each point with _nmod_poly_evaluate_nmod.
void _nmod_poly_evaluate_nmod_vec_fast(nn_ptr ys, nn_srcptr coeffs, slong ilen, nn_srcptr xs, slong olen, nmod_t mod)void nmod_poly_evaluate_nmod_vec_fast(nn_ptr ys, const nmod_poly_t poly, nn_srcptr xs, slong olen)The same with a temporary subproduct tree.
Full documentationvoid _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.
nn_ptr * _nmod_poly_tree_alloc(slong len)void _nmod_poly_tree_free(nn_ptr * tree, slong len)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 , , in the space allocated by _nmod_poly_tree_alloc.
void _nmod_poly_interpolation_weights(nn_ptr w, const nn_ptr * tree, slong len, nmod_t mod)Sets w[i] to the barycentric weight , where for the points of tree.
void _nmod_poly_interpolate_nmod_vec_fast_precomp(nn_ptr poly, nn_srcptr ys, const nn_ptr * tree, nn_srcptr weights, slong len, nmod_t mod)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 up the tree (fast Lagrange interpolation). Writes len coefficients.
void _nmod_poly_interpolate_nmod_vec(nn_ptr poly, nn_srcptr xs, nn_srcptr ys, slong len, nmod_t mod)void nmod_poly_interpolate_nmod_vec(nmod_poly_t poly, nn_srcptr xs, nn_srcptr ys, slong len)Set poly to the unique polynomial of length at most len with for . The points must be distinct and all values reduced. Uses the Newton form for , the barycentric form for and fast interpolation otherwise. The underscore version requires , writes len coefficients and does not allow poly to overlap xs or ys.
void _nmod_poly_interpolate_nmod_vec_fast(nn_ptr poly, nn_srcptr xs, nn_srcptr ys, slong len, nmod_t mod)void nmod_poly_interpolate_nmod_vec_fast(nmod_poly_t poly, nn_srcptr xs, nn_srcptr ys, slong len)The same by fast Lagrange interpolation with a temporary subproduct tree, in operations.
Full documentationvoid _nmod_poly_interpolate_nmod_vec_newton(nn_ptr poly, nn_srcptr xs, nn_srcptr ys, slong len, nmod_t mod)void nmod_poly_interpolate_nmod_vec_newton(nmod_poly_t poly, nn_srcptr xs, nn_srcptr ys, slong n)The same by divided differences, followed by a conversion from the Newton basis to the monomial basis. It uses multiplications and modular inversions.
void _nmod_poly_interpolate_nmod_vec_barycentric(nn_ptr poly, nn_srcptr xs, nn_srcptr ys, slong len, nmod_t mod)void nmod_poly_interpolate_nmod_vec_barycentric(nmod_poly_t poly, nn_srcptr xs, nn_srcptr ys, slong len)The same by the Lagrange formula , with and as above, in multiplications and len inversions.
void _nmod_poly_product_roots_nmod_vec(nn_ptr poly, nn_srcptr xs, slong n, nmod_t mod)void nmod_poly_product_roots_nmod_vec(nmod_poly_t poly, nn_srcptr xs, slong n)Set poly to , for reduced . The underscore version writes coefficients and does not allow aliasing. Uses the quadratic algorithm for and balanced products above.
Geometric progressions#
Evaluation and interpolation at the points of a geometric progression cost instead of : evaluation is a single middle product by Bluestein's chirp transform [Blu1970] [RSR1969], using , and interpolation is two products [BS2005]. The functions take with , so that needs no square root, and use the points . The value must be reduced and invertible modulo . For interpolation and extrapolation the points must be distinct with invertible, which for prime means that the multiplicative order of exceeds the number of points. See Geometric progressions.
Precomputed data for evaluation, interpolation and extrapolation at the points : 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.
void nmod_geometric_progression_init(nmod_geometric_progression_t G, ulong r, slong len, nmod_t mod)void _nmod_geometric_progression_init_function(nmod_geometric_progression_t G, ulong r, slong len, nmod_t mod, ulong function)Initialise G for the points . 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.
void _nmod_geometric_progression_init_fft(nmod_geometric_progression_t G, slong ev_len, slong int_len, slong ext_len)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 ( instead of ) and interpolation (about ), and may need fewer primes; the extrapolation transforms have length 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.
Frees the memory used by G.
void _nmod_poly_evaluate_geometric_nmod_vec_fast_precomp(nn_ptr vs, nn_srcptr poly, slong ilen, const nmod_geometric_progression_t G, slong olen, nmod_t mod)Sets vs[i] to for , using G prepared for evaluation. Requires G->len.
void _nmod_poly_evaluate_geometric_nmod_vec_fast(nn_ptr ys, nn_srcptr coeffs, slong ilen, ulong r, slong olen, nmod_t mod)void nmod_poly_evaluate_geometric_nmod_vec_fast(nn_ptr ys, const nmod_poly_t poly, ulong r, slong olen)The same with a temporary precomputation for evaluation.
void _nmod_poly_evaluate_geometric_nmod_vec_iter(nn_ptr ys, nn_srcptr coeffs, slong ilen, ulong r, slong olen, nmod_t mod)void nmod_poly_evaluate_geometric_nmod_vec_iter(nn_ptr ys, const nmod_poly_t poly, ulong r, slong olen)The same by evaluating at each point with _nmod_poly_evaluate_nmod. No condition on .
void _nmod_poly_interpolate_geometric_nmod_vec_fast_precomp(nn_ptr poly, nn_srcptr v, const nmod_geometric_progression_t G, slong len, nmod_t mod)void nmod_poly_interpolate_geometric_nmod_vec_fast_precomp(nmod_poly_t poly, nn_srcptr v, const nmod_geometric_progression_t G, slong len)Set poly to the polynomial of length at most len taking the values v[i] at , , using G prepared for interpolation. Requires G->len. The underscore version writes len coefficients and does not allow poly to overlap v.
void nmod_poly_interpolate_geometric_nmod_vec_fast(nmod_poly_t poly, ulong r, nn_srcptr ys, slong len)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)void nmod_poly_extrapolate_geometric_precomp(nn_ptr oval, slong olen, nn_srcptr ival, slong ilen, slong offset, const nmod_geometric_progression_t G)Given the values ival of a polynomial of degree less than at ilen consecutive points of the progression, compute its values oval at olen consecutive points starting offset positions later, without computing . The points must not overlap: (forward) or (backward).
Composition#
Composition and the Taylor shift ; 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 . The underscore version requires , writes coefficients and does not allow aliasing.
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.
Obsolete names, defined as _nmod_poly_compose and nmod_poly_compose.
void _nmod_poly_taylor_shift(nn_ptr poly, ulong c, slong len, nmod_t mod)void nmod_poly_taylor_shift(nmod_poly_t g, const nmod_poly_t f, ulong c)Set , for reduced ; the underscore version works in place on (poly, len). Uses Horner's rule for or , and for and , and the convolution method otherwise, which requires to be invertible modulo (for prime , guaranteed by ); otherwise FLINT_IMPINV is thrown.
void _nmod_poly_taylor_shift_horner(nn_ptr poly, ulong c, slong len, nmod_t mod)void nmod_poly_taylor_shift_horner(nmod_poly_t g, const nmod_poly_t f, ulong c)The Taylor shift by Horner's rule, with additions and multiplications. Works for every modulus.
Full documentationvoid _nmod_poly_taylor_shift_convolution(nn_ptr poly, ulong c, slong len, nmod_t mod)void nmod_poly_taylor_shift_convolution(nmod_poly_t g, const nmod_poly_t f, ulong c)The Taylor shift as one product of length len, using [ASU1975] [GG1997], in operations. Requires to be invertible modulo .
Modular composition#
Modular composition computes . By the algorithm of Brent and Kung [BrentKung1978] it costs operations for , using a matrix product of size by . With , the matrix holding in its rows can be precomputed and reused for many . All functions require with invertible leading coefficient and allow res to be any input (the non-underscore versions). See Modular composition.
nmod_poly.
void _nmod_poly_compose_mod(nn_ptr res, nn_srcptr f, slong lenf, nn_srcptr g, nn_srcptr h, slong lenh, nmod_t mod)void nmod_poly_compose_mod(nmod_poly_t res, const nmod_poly_t f, const nmod_poly_t g, const nmod_poly_t h)Set res to . The non-underscore version accepts any and and throws FLINT_DIVZERO for . The underscore version requires , and reduced and zero-padded to length , writes coefficients and does not allow aliasing. It uses Horner's rule if or , and the Brent–Kung algorithm otherwise.
void _nmod_poly_compose_mod_horner(nn_ptr res, nn_srcptr f, slong lenf, nn_srcptr g, nn_srcptr h, slong lenh, nmod_t mod)void nmod_poly_compose_mod_horner(nmod_poly_t res, const nmod_poly_t f, const nmod_poly_t g, const nmod_poly_t h)Modular composition by Horner's rule, with multiplications modulo , and the conventions of _nmod_poly_compose_mod.
void _nmod_poly_compose_mod_brent_kung(nn_ptr res, nn_srcptr f, slong lenf, nn_srcptr g, nn_srcptr h, slong lenh, nmod_t mod)void nmod_poly_compose_mod_brent_kung(nmod_poly_t res, const nmod_poly_t f, const nmod_poly_t g, const nmod_poly_t h)Modular composition by the Brent–Kung algorithm, with the conventions of _nmod_poly_compose_mod. Requires (); the non-underscore version throws FLINT_ERROR otherwise.
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 by the Brent–Kung algorithm, given the inverse poly3inv of the reversal of poly3 as for nmod_poly_mulmod_preinv. Requires ; the underscore version also requires poly2 reduced and zero-padded to length .
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 matrix to for , where and , given the inverse poly2inv of the reversal of poly2. 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 .
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)void nmod_poly_compose_mod_brent_kung_precomp_preinv(nmod_poly_t res, const nmod_poly_t poly1, const nmod_mat_t A, const nmod_poly_t poly3, const nmod_poly_t poly3inv)Set res to , where is the matrix computed by nmod_poly_precompute_matrix for and poly3. Requires . This is the function to use for many compositions with the same and modulus, as in the computation of Frobenius powers in polynomial factorisation [GatSho1992] [KalSho1998].
void _nmod_poly_reduce_matrix_mod_poly(nmod_mat_t A, const nmod_mat_t B, const nmod_poly_t f)Initialises as an matrix, , , and sets row 0 to 1 and row to row of reduced modulo for . must not be initialised before the call; needs at least rows and at least 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 , where is row of the matrix , h has length and . This is the last step of the Brent–Kung algorithm, with ; it uses Horner's rule for 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 , where poly2 must have constant term 0 (the non-underscore version throws FLINT_ERROR otherwise). The underscore version requires , writes coefficients and does not allow aliasing.
void nmod_poly_revert_series(nmod_poly_t Qinv, const nmod_poly_t Q, slong n)Set Qinv to the compositional inverse of the power series modulo , so that . Requires and invertible; the non-underscore version throws FLINT_ERROR otherwise. The underscore version writes coefficients and does not allow aliasing.
Square roots#
void nmod_poly_sqrt_series(nmod_poly_t g, const nmod_poly_t h, slong n)void nmod_poly_invsqrt_series(nmod_poly_t g, const nmod_poly_t h, slong n)int _nmod_poly_sqrt(nn_ptr s, nn_srcptr p, slong len, nmod_t mod)int nmod_poly_sqrt(nmod_poly_t b, const nmod_poly_t a)If is the square of a polynomial, set to a square root and return 1; otherwise return 0 (and set ). Requires a prime modulus. The underscore version requires , writes coefficients and does not allow aliasing.
MorePower sums#
The power sums of a polynomial with roots (with multiplicity, in an algebraic closure) are . They determine if is invertible, by Newton's identities , and can be computed in operations from the series , where is the reversal of [Sch1982b] [BFSS2006]. Here the power sum series of is with .
void nmod_poly_power_sums(nmod_poly_t res, const nmod_poly_t poly, slong n)Set res to . The non-underscore version accepts any nonzero poly with invertible leading coefficient (throwing FLINT_ERROR for zero) and handles factors . The underscore version requires poly monic and writes coefficients. Uses Newton's identities for and the series formula otherwise.
void nmod_poly_power_sums_naive(nmod_poly_t res, const nmod_poly_t poly, slong n)void nmod_poly_power_sums_schoenhage(nmod_poly_t res, const nmod_poly_t poly, slong n)The power sums by Newton's identities, in operations, and by the series formula with one power series division, in operations. The underscore versions require poly monic.
void _nmod_poly_power_sums_to_poly(nn_ptr res, nn_srcptr poly, slong len, nmod_t mod)void nmod_poly_power_sums_to_poly(nmod_poly_t res, const nmod_poly_t Q)Set res to the monic polynomial of degree whose power sum series is (modulo , the higher power sums being determined by of them). Requires invertible modulo . For the result is 1. The underscore version writes coefficients. Uses Newton's identities if or and the exponential formula otherwise.
void _nmod_poly_power_sums_to_poly_naive(nn_ptr res, nn_srcptr poly, slong len, nmod_t mod)void nmod_poly_power_sums_to_poly_naive(nmod_poly_t res, const nmod_poly_t Q)void _nmod_poly_power_sums_to_poly_schoenhage(nn_ptr res, nn_srcptr poly, slong len, nmod_t mod)void nmod_poly_power_sums_to_poly_schoenhage(nmod_poly_t res, const nmod_poly_t Q)The same by Newton's identities, in operations, and by the exponential formula, in operations.
Elementary functions of power series#
For a power series these functions compute , where
with integration constants 0, and the trigonometric and hyperbolic functions are defined by the usual relations to . The constant term of must be 1 for and 0 for all other functions; the non-underscore functions throw FLINT_ERROR otherwise. The coefficients involve for , so the modulus must be a prime , and also ; this is not checked. All functions cost operations for large , typically with Newton iteration [HZ2004] [BZ2011], and use quadratic algorithms for small . The underscore versions require , write coefficients, and allow to be the same array as unless stated otherwise.
void nmod_poly_exp_series(nmod_poly_t f, const nmod_poly_t h, slong n)Set .
MoreSets and modulo , currently by _nmod_poly_exp_series followed by _nmod_poly_inv_series. Requires and does not allow aliasing.
void nmod_poly_log_series(nmod_poly_t res, const nmod_poly_t f, slong n)Set , for with constant term 1, as the integral of .
void nmod_poly_atan_series(nmod_poly_t g, const nmod_poly_t h, slong n)void nmod_poly_atanh_series(nmod_poly_t g, const nmod_poly_t h, slong n)void nmod_poly_asin_series(nmod_poly_t g, const nmod_poly_t h, slong n)void nmod_poly_asinh_series(nmod_poly_t g, const nmod_poly_t h, slong n)Set to , , and modulo , from the integrals above.
void nmod_poly_sin_series(nmod_poly_t g, const nmod_poly_t h, slong n)void nmod_poly_cos_series(nmod_poly_t g, const nmod_poly_t h, slong n)void nmod_poly_tan_series(nmod_poly_t g, const nmod_poly_t h, slong n)void nmod_poly_tanh_series(nmod_poly_t g, const nmod_poly_t h, slong n)Set to , , and modulo .
void _nmod_poly_sinh_series(nn_ptr g, nn_srcptr h, slong n, nmod_t mod)void nmod_poly_sinh_series(nmod_poly_t g, const nmod_poly_t h, slong n)void _nmod_poly_cosh_series(nn_ptr g, nn_srcptr h, slong n, nmod_t mod)void nmod_poly_cosh_series(nmod_poly_t g, const nmod_poly_t h, slong n)Set to and modulo , using _nmod_poly_exp_expinv_series. The underscore versions read exactly coefficients of (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.
int nmod_poly_find_distinct_nonzero_roots(ulong * roots, const nmod_poly_t P)If the nonzero polynomial of degree has distinct nonzero roots modulo the prime (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 the result is 0 for .
void _nmod_poly_split_rabin(nmod_poly_t a, nmod_poly_t b, const nmod_poly_t f, nmod_poly_t t, nmod_poly_t t2, flint_rand_t randstate)For monic of degree at least 2 with distinct nonzero roots modulo an odd prime, find a factorisation with by trying random until is a proper factor. t and t2 are temporaries.
Irreducible and Conway polynomials#
void nmod_poly_minimal_irreducible(nmod_poly_t res, ulong n)Sets res to a monic irreducible polynomial of degree over the prime field , the modulus of res, with the least possible number of nonzero terms: a binomial 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 () or pentanomial () always does.
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 for = prime and = deg, writes its coefficients to op and returns 1; otherwise returns 0 (see Defining polynomials). The tables cover the primes below 109988, with all tabulated degrees for and degree bounds that decrease with above (12 for , then 9, 6, 4).
ulong _nmod_poly_conway_rand(slong * degree, flint_rand_t state, int type)Returns a random prime and sets degree to a random 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 , 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 , where is input and = inflation . For the result is the constant .
void nmod_poly_deflate(nmod_poly_t result, const nmod_poly_t input, slong deflation)Sets result to , where is input and = deflation must divide the exponent of every nonzero term (not checked). Throws FLINT_DIVZERO for .
slong nmod_poly_deflation(const nmod_poly_t input)Returns the largest such that input is a polynomial in , 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 and values , these functions find the polynomial of least degree with . The moduli are combined pairwise along a binary tree sorted by degree; each node stores an idempotent with modulo one child and modulo the other, and computes . 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 of the program, with the indices of , and (negative indices refer to the inputs), the idempotent and the modulus .
Initialise and free CRT.
int nmod_poly_multi_crt_precompute(nmod_poly_multi_crt_t CRT, const nmod_poly_struct * moduli, slong len)int nmod_poly_multi_crt_precompute_p(nmod_poly_multi_crt_t CRT, const nmod_poly_struct * const * moduli, slong len)Prepare CRT for the moduli, given as an array of polynomials or of pointers. Return 1 on success, which happens if and only if either 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.
void nmod_poly_multi_crt_precomp(nmod_poly_t output, const nmod_poly_multi_crt_t CRT, const nmod_poly_struct * values)void nmod_poly_multi_crt_precomp_p(nmod_poly_t output, const nmod_poly_multi_crt_t CRT, const nmod_poly_struct * const * values)Set output to the polynomial of least degree congruent to values[i] modulo the -th modulus of CRT, for all . 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(nmod_poly_struct * outputs, const nmod_poly_multi_crt_t CRT, const nmod_poly_struct * inputs)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 points have been added, nmod_berlekamp_massey_reduce computes polynomials of the extended Euclidean remainder sequence of and with
Then , so writing , the recurrence holds for . If , the recurrence holds for the whole sequence (), and 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 points, whose degree can be close to and which is then not determined uniquely, has degree at most . 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 and of the last two steps of the remainder sequence.
Initialise B with an empty sequence modulo the prime , and free it.
Empty the sequence of B; the second function also changes the prime to .
void nmod_berlekamp_massey_add_points(nmod_berlekamp_massey_t B, const ulong * a, slong count)void nmod_berlekamp_massey_add_zeros(nmod_berlekamp_massey_t B, slong count)Append count reduced points, count zeros, or one point to the sequence. The polynomials are updated only by nmod_berlekamp_massey_reduce.
Brings and up to date with all points added and returns 1 if changed, 0 otherwise.
Moreconst ulong * nmod_berlekamp_massey_points(const nmod_berlekamp_massey_t B)Return the number of points added and a pointer to them (which may be NULL if there are none).
const nmod_poly_struct * nmod_berlekamp_massey_V_poly(const nmod_berlekamp_massey_t B)const nmod_poly_struct * nmod_berlekamp_massey_R_poly(const nmod_berlekamp_massey_t B)Return the polynomials and as of the last call to nmod_berlekamp_massey_reduce.
void nmod_berlekamp_massey_print(const nmod_berlekamp_massey_t B)Prints 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 . They are the building blocks of Kronecker substitution.
void _nmod_poly_bit_pack(nn_ptr res, nn_srcptr poly, slong len, flint_bitcnt_t bits)Writes to res as limbs. Requires , and every coefficient less than .
void _nmod_poly_bit_unpack(nn_ptr res, slong nlo, slong nhi, nn_srcptr mpn, flint_bitcnt_t bits, nmod_t mod)Reads the bit fields of width bits from mpn, reduces them modulo and writes them to res[0], ..., res[nhi - nlo - 1]. The fields may hold any value. Requires .
void nmod_poly_bit_pack(fmpz_t f, const nmod_poly_t poly, flint_bitcnt_t bit_size)Sets . Every coefficient must be less than ; . For bit_size = 0 or the zero polynomial, .
void nmod_poly_bit_unpack(nmod_poly_t poly, const fmpz_t f, flint_bitcnt_t bit_size)Sets poly to the polynomial whose coefficients are the bit fields of width bit_size of , reduced modulo ; the inverse of nmod_poly_bit_pack for reduced coefficients. Throws FLINT_ERROR for . For bit_size = 0 the result is 0.
Write zero bits followed by the values op[0], op[s], ..., op[(n-1) s] in fields of bits to res, and zero-pad the output to limbs if . Each value must be less than . The pack1 version requires , the other . Used by _nmod_poly_mul_KS2 and _nmod_poly_mul_KS4.
Skip bits of op and extract fields of bits, writing each as one, two or three words to res. _nmod_poly_KS2_unpack1 requires , unpack2 , unpack3 ; _nmod_poly_KS2_unpack dispatches on .
Reduces values of words each, stored consecutively in op, modulo , writing them to res[0], res[s], ... with stride .
void _nmod_poly_KS2_recover_reduce(nn_ptr res, slong s, nn_srcptr op1, nn_srcptr op2, slong n, ulong b, nmod_t mod)void _nmod_poly_KS2_recover_reduce1(nn_ptr res, slong s, nn_srcptr op1, nn_srcptr op2, slong n, ulong b, nmod_t mod)void _nmod_poly_KS2_recover_reduce2(nn_ptr res, slong s, nn_srcptr op1, nn_srcptr op2, slong n, ulong b, nmod_t mod)void _nmod_poly_KS2_recover_reduce2b(nn_ptr res, slong s, nn_srcptr op1, nn_srcptr op2, slong n, ulong b, nmod_t mod)void _nmod_poly_KS2_recover_reduce3(nn_ptr res, slong s, nn_srcptr op1, nn_srcptr op2, slong n, ulong b, nmod_t mod)Recover coefficients of bits from two sequences of digits of bits, unpacked from an integer product evaluated at (op1, low digits first) and from the product of the reversed polynomials (op2), propagating the borrows between them; reduce the coefficients modulo and write them with stride . Used by _nmod_poly_mul_KS4. The variants require (1), (2), (2b) and (3); the version without suffix dispatches on .
Internal functions#
The following helpers are declared in the header for use by other modules and by the functions above.
void _nmod_poly_divrem_basecase_preinv1(nn_ptr Q, nn_ptr R, nn_srcptr A, slong A_len, nn_srcptr B, slong B_len, ulong invB, nmod_t mod)_nmod_poly_divrem_basecase given invB . Same conventions; may be the same array as .
void _nmod_poly_divrem_q1_preinv1(nn_ptr Q, nn_ptr R, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, ulong invL, nmod_t mod)Division with remainder for , the typical step of the Euclidean algorithm, given invL . Writes two coefficients to and to . may be the same array as , but must not overlap . The two quotient coefficients are computed first, and each remainder coefficient is then formed with a single reduction, using Lemire, Barrett or Möller–Granlund reduction depending on the size of .
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.
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).
@misc{flint-doc-nmod-poly-index,
author = {{The FLINT team}},
title = {{nmod\_poly.h (module overview)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/nmod_poly/index.html},
note = {Generated 2026-11-02}
}