2474 lines
101 KiB
Plaintext
2474 lines
101 KiB
Plaintext
/*=============================================================================
|
|
|
|
This file is part of FLINT.
|
|
|
|
FLINT is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
FLINT is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with FLINT; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
=============================================================================*/
|
|
/******************************************************************************
|
|
|
|
Copyright (C) 2010 William Hart
|
|
Copyright (C) 2011 Fredrik Johansson
|
|
Copyright (C) 2011 Sebastian Pancratz
|
|
|
|
******************************************************************************/
|
|
|
|
*******************************************************************************
|
|
|
|
Helper functions
|
|
|
|
*******************************************************************************
|
|
|
|
int signed_mpn_sub_n(mp_ptr res, mp_srcptr op1, mp_srcptr op2, slong n)
|
|
|
|
If \code{op1 >= op2} return 0 and set \code{res} to \code{op1 - op2}
|
|
else return 1 and set \code{res} to \code{op2 - op1}.
|
|
|
|
*******************************************************************************
|
|
|
|
Memory management
|
|
|
|
*******************************************************************************
|
|
|
|
void nmod_poly_init(nmod_poly_t poly, mp_limb_t n)
|
|
|
|
Initialises \code{poly}. It will have coefficients modulo~$n$.
|
|
|
|
void nmod_poly_init_preinv(nmod_poly_t poly, mp_limb_t n, mp_limb_t ninv)
|
|
|
|
Initialises \code{poly}. It will have coefficients modulo~$n$.
|
|
The caller supplies a precomputed inverse limb generated by
|
|
\code{n_preinvert_limb()}.
|
|
|
|
void nmod_poly_init2(nmod_poly_t poly, mp_limb_t n, slong alloc)
|
|
|
|
Initialises \code{poly}. It will have coefficients modulo~$n$.
|
|
Up to \code{alloc} coefficients may be stored in \code{poly}.
|
|
|
|
void nmod_poly_init2_preinv(nmod_poly_t poly,
|
|
mp_limb_t n, mp_limb_t ninv, slong alloc)
|
|
|
|
Initialises \code{poly}. It will have coefficients modulo~$n$.
|
|
The caller supplies a precomputed inverse limb generated by
|
|
\code{n_preinvert_limb()}. Up to \code{alloc} coefficients may
|
|
be stored in \code{poly}.
|
|
|
|
void nmod_poly_realloc(nmod_poly_t poly, slong alloc)
|
|
|
|
Reallocates \code{poly} to the given length. If the current
|
|
length is less than \code{alloc}, the polynomial is truncated
|
|
and normalised. If \code{alloc} is zero, the polynomial is
|
|
cleared.
|
|
|
|
void nmod_poly_clear(nmod_poly_t poly)
|
|
|
|
Clears the polynomial and releases any memory it used. The polynomial
|
|
cannot be used again until it is initialised.
|
|
|
|
void nmod_poly_fit_length(nmod_poly_t poly, slong alloc)
|
|
|
|
Ensures \code{poly} has space for at least \code{alloc} coefficients.
|
|
This function only ever grows the allocated space, so no data loss can
|
|
occur.
|
|
|
|
void _nmod_poly_normalise(nmod_poly_t poly)
|
|
|
|
Internal function for normalising a polynomial so that the top
|
|
coefficient, if there is one at all, is not zero.
|
|
|
|
*******************************************************************************
|
|
|
|
Polynomial properties
|
|
|
|
*******************************************************************************
|
|
|
|
slong nmod_poly_length(const nmod_poly_t poly)
|
|
|
|
Returns the length of the polynomial \code{poly}. The zero polynomial
|
|
has length zero.
|
|
|
|
slong nmod_poly_degree(const nmod_poly_t poly)
|
|
|
|
Returns the degree of the polynomial \code{poly}. The zero polynomial
|
|
is deemed to have degree~$-1$.
|
|
|
|
mp_limb_t nmod_poly_modulus(const nmod_poly_t poly)
|
|
|
|
Returns the modulus of the polynomial \code{poly}. This will be a
|
|
positive integer.
|
|
|
|
mp_bitcnt_t nmod_poly_max_bits(const nmod_poly_t poly)
|
|
|
|
Returns the maximum number of bits of any coefficient of \code{poly}.
|
|
|
|
*******************************************************************************
|
|
|
|
Assignment and basic manipulation
|
|
|
|
*******************************************************************************
|
|
|
|
void nmod_poly_set(nmod_poly_t a, const nmod_poly_t b)
|
|
|
|
Sets \code{a} to a copy of \code{b}.
|
|
|
|
void nmod_poly_swap(nmod_poly_t poly1, nmod_poly_t poly2)
|
|
|
|
Efficiently swaps \code{poly1} and \code{poly2} by swapping pointers
|
|
internally.
|
|
|
|
void nmod_poly_zero(nmod_poly_t res)
|
|
|
|
Sets \code{res} to the zero polynomial.
|
|
|
|
void nmod_poly_truncate(nmod_poly_t poly, slong len)
|
|
|
|
Truncates \code{poly} to the given length and normalises it.
|
|
If \code{len} is greater than the current length of \code{poly},
|
|
then nothing happens.
|
|
|
|
void _nmod_poly_reverse(mp_ptr output, mp_srcptr input, slong len, slong m)
|
|
|
|
Sets \code{output} to the reverse of \code{input}, which is of length
|
|
\code{len}, but thinking of it as a polynomial of length~\code{m},
|
|
notionally zero-padded if necessary. The length~\code{m} must be
|
|
non-negative, but there are no other restrictions. The polynomial
|
|
\code{output} must have space for \code{m} coefficients.
|
|
|
|
void nmod_poly_reverse(nmod_poly_t output, const nmod_poly_t input, slong m)
|
|
|
|
Sets \code{output} to the reverse of \code{input}, thinking of it as
|
|
a polynomial of length~\code{m}, notionally zero-padded if necessary).
|
|
The length~\code{m} must be non-negative, but there are no other
|
|
restrictions. The output polynomial will be set to length~\code{m}
|
|
and then normalised.
|
|
|
|
*******************************************************************************
|
|
|
|
Randomization
|
|
|
|
*******************************************************************************
|
|
|
|
void nmod_poly_randtest(nmod_poly_t poly, flint_rand_t state, slong len)
|
|
|
|
Generates a random polynomial with length up to \code{len}.
|
|
|
|
void
|
|
nmod_poly_randtest_irreducible(nmod_poly_t poly, flint_rand_t state, slong len)
|
|
|
|
Generates a random irreducible polynomial with length up to \code{len}.
|
|
|
|
void nmod_poly_randtest_monic(nmod_poly_t poly, flint_rand_t state, slong len)
|
|
|
|
Generates a random monic polynomial with length \code{len}.
|
|
|
|
void
|
|
nmod_poly_randtest_monic_irreducible(nmod_poly_t poly, flint_rand_t state,
|
|
slong len)
|
|
|
|
Generates a random monic irreducible polynomial with length \code{len}.
|
|
|
|
|
|
void
|
|
nmod_poly_randtest_trinomial(nmod_poly_t poly, flint_rand_t state, slong len)
|
|
|
|
Generates a random monic trinomial of length \code{len}.
|
|
|
|
int
|
|
nmod_poly_randtest_trinomial_irreducible(nmod_poly_t poly, flint_rand_t state,
|
|
slong len, slong max_attempts)
|
|
|
|
Attempts to set \code{poly} to a monic irreducible trinomial of
|
|
length \code{len}. It will generate up to \code{max_attempts}
|
|
trinomials in attempt to find an irreducible one. If
|
|
\code{max_attempts} is \code{0}, then it will keep generating
|
|
trinomials until an irreducible one is found. Returns $1$ if one
|
|
is found and $0$ otherwise.
|
|
|
|
void
|
|
nmod_poly_randtest_pentomial(nmod_poly_t poly, flint_rand_t state, slong len)
|
|
|
|
Generates a random monic pentomial of length \code{len}.
|
|
|
|
int
|
|
nmod_poly_randtest_pentomial_irreducible(nmod_poly_t poly, flint_rand_t state,
|
|
slong len, slong max_attempts)
|
|
|
|
Attempts to set \code{poly} to a monic irreducible pentomial of
|
|
length \code{len}. It will generate up to \code{max_attempts}
|
|
pentomials in attempt to find an irreducible one. If
|
|
\code{max_attempts} is \code{0}, then it will keep generating
|
|
pentomials until an irreducible one is found. Returns $1$ if one
|
|
is found and $0$ otherwise.
|
|
|
|
void
|
|
nmod_poly_randtest_sparse_irreducible(nmod_poly_t poly, flint_rand_t state,
|
|
slong len)
|
|
|
|
Attempts to set \code{poly} to a sparse, monic irreducible polynomial
|
|
with length \code{len}. It attempts to find an irreducible
|
|
trinomial. If that does not succeed, it attempts to find a
|
|
irreducible pentomial. If that fails, then \code{poly} is just
|
|
set to a random monic irreducible polynomial.
|
|
|
|
*******************************************************************************
|
|
|
|
Getting and setting coefficients
|
|
|
|
*******************************************************************************
|
|
|
|
ulong nmod_poly_get_coeff_ui(const nmod_poly_t poly, slong j)
|
|
|
|
Returns the coefficient of \code{poly} at index~\code{j}, where
|
|
coefficients are numbered with zero being the constant coefficient,
|
|
and returns it as an \code{ulong}. If \code{j} refers to a
|
|
coefficient beyond the end of \code{poly}, zero is returned.
|
|
|
|
void nmod_poly_set_coeff_ui(nmod_poly_t poly, slong j, ulong c)
|
|
|
|
Sets the coefficient of \code{poly} at index \code{j}, where
|
|
coefficients are numbered with zero being the constant coefficient,
|
|
to the value \code{c} reduced modulo the modulus of \code{poly}.
|
|
If \code{j} refers to a coefficient beyond the current end of \code{poly},
|
|
the polynomial is first resized, with intervening coefficients being
|
|
set to zero.
|
|
|
|
*******************************************************************************
|
|
|
|
Input and output
|
|
|
|
*******************************************************************************
|
|
|
|
char * nmod_poly_get_str(const nmod_poly_t poly)
|
|
|
|
Writes \code{poly} to a string representation. The format is as
|
|
described for \code{nmod_poly_print()}. The string must be freed by the
|
|
user when finished. For this it is sufficient to call \code{flint_free()}.
|
|
|
|
int nmod_poly_set_str(nmod_poly_t poly, const char * s)
|
|
|
|
Reads \code{poly} from a string \code{s}. The format is as described
|
|
for \code{nmod_poly_print()}. If a polynomial in the correct format
|
|
is read, a positive value is returned, otherwise a non-positive value
|
|
is returned.
|
|
|
|
int nmod_poly_print(const nmod_poly_t a)
|
|
|
|
Prints the polynomial to \code{stdout}. The length is printed,
|
|
followed by a space, then the modulus. If the length is zero this is
|
|
all that is printed, otherwise two spaces followed by a space
|
|
separated list of coefficients is printed, beginning with the constant
|
|
coefficient.
|
|
|
|
In case of success, returns a positive value. In case of failure,
|
|
returns a non-positive value.
|
|
|
|
int nmod_poly_fread(FILE * f, nmod_poly_t poly)
|
|
|
|
Reads \code{poly} from the file stream \code{f}. If this is a file
|
|
that has just been written, the file should be closed then opened
|
|
again. The format is as described for \code{nmod_poly_print()}. If a
|
|
polynomial in the correct format is read, a positive value is returned,
|
|
otherwise a non-positive value is returned.
|
|
|
|
int nmod_poly_fprint(FILE * f, const nmod_poly_t poly)
|
|
|
|
Writes a polynomial to the file stream \code{f}. If this is a file
|
|
then the file should be closed and reopened before being read.
|
|
The format is as described for \code{nmod_poly_print()}. If a
|
|
polynomial in the correct format is read, a positive value is returned,
|
|
otherwise a non-positive value is returned. If an error occurs
|
|
whilst writing to the file, an error message is printed.
|
|
|
|
In case of success, returns a positive value. In case of failure,
|
|
returns a non-positive value.
|
|
|
|
int nmod_poly_read(nmod_poly_t poly)
|
|
|
|
Read \code{poly} from \code{stdin}. The format is as described for
|
|
\code{nmod_poly_print()}. If a polynomial in the correct format is read, a
|
|
positive value is returned, otherwise a non-positive value is returned.
|
|
|
|
*******************************************************************************
|
|
|
|
Comparison
|
|
|
|
*******************************************************************************
|
|
|
|
int nmod_poly_equal(const nmod_poly_t a, const nmod_poly_t b)
|
|
|
|
Returns~$1$ if the polynomials are equal, otherwise~$0$.
|
|
|
|
int nmod_poly_is_zero(const nmod_poly_t poly)
|
|
|
|
Returns~$1$ if the polynomial \code{poly} is the zero polynomial,
|
|
otherwise returns~$0$.
|
|
|
|
int nmod_poly_is_one(const nmod_poly_t poly)
|
|
|
|
Returns~$1$ if the polynomial \code{poly} is the constant polynomial 1,
|
|
otherwise returns~$0$.
|
|
|
|
*******************************************************************************
|
|
|
|
Shifting
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_shift_left(mp_ptr res, mp_srcptr poly, slong len, slong k)
|
|
|
|
Sets \code{(res, len + k)} to \code{(poly, len)} shifted left by
|
|
\code{k} coefficients. Assumes that \code{res} has space for
|
|
\code{len + k} coefficients.
|
|
|
|
void nmod_poly_shift_left(nmod_poly_t res, const nmod_poly_t poly, slong k)
|
|
|
|
Sets \code{res} to \code{poly} shifted left by \code{k} coefficients,
|
|
i.e.\ multiplied by $x^k$.
|
|
|
|
void _nmod_poly_shift_right(mp_ptr res, mp_srcptr poly, slong len, slong k)
|
|
|
|
Sets \code{(res, len - k)} to \code{(poly, len)} shifted left by
|
|
\code{k} coefficients. It is assumed that \code{k <= len} and that
|
|
\code{res} has space for at least \code{len - k} coefficients.
|
|
|
|
void nmod_poly_shift_right(nmod_poly_t res, const nmod_poly_t poly, slong k)
|
|
|
|
Sets \code{res} to \code{poly} shifted right by \code{k} coefficients,
|
|
i.e.\ divide by $x^k$ and throws away the remainder. If \code{k} is
|
|
greater than or equal to the length of \code{poly}, the result is the
|
|
zero polynomial.
|
|
|
|
*******************************************************************************
|
|
|
|
Addition and subtraction
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_add(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Sets \code{res} to the sum of \code{(poly1, len1)} and
|
|
\code{(poly2, len2)}. There are no restrictions on the lengths.
|
|
|
|
void nmod_poly_add(nmod_poly_t res, const nmod_poly_t poly1,
|
|
const nmod_poly_t poly2)
|
|
|
|
Sets \code{res} to the sum of \code{poly1} and \code{poly2}.
|
|
|
|
void _nmod_poly_sub(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Sets \code{res} to the difference of \code{(poly1, len1)} and
|
|
\code{(poly2, len2)}. There are no restrictions on the lengths.
|
|
|
|
void nmod_poly_sub(nmod_poly_t res, const nmod_poly_t poly1,
|
|
const nmod_poly_t poly2)
|
|
|
|
Sets \code{res} to the difference of \code{poly1} and \code{poly2}.
|
|
|
|
void nmod_poly_neg(nmod_poly_t res, const nmod_poly_t poly)
|
|
|
|
Sets \code{res} to the negation of \code{poly}.
|
|
|
|
*******************************************************************************
|
|
|
|
Scalar multiplication and division
|
|
|
|
*******************************************************************************
|
|
|
|
void nmod_poly_scalar_mul_nmod(nmod_poly_t res,
|
|
const nmod_poly_t poly, ulong c)
|
|
|
|
Sets \code{res} to \code{(poly, len)} multiplied by~$c$,
|
|
where~$c$ is reduced modulo the modulus of \code{poly}.
|
|
|
|
void _nmod_poly_make_monic(mp_ptr output,
|
|
mp_srcptr input, slong len, nmod_t mod)
|
|
|
|
Sets \code{output} to be the scalar multiple of \code{input} of
|
|
length \code{len > 0} that has leading coefficient one, if such a
|
|
polynomial exists. If the leading coefficient of \code{input} is not
|
|
invertible, \code{output} is set to the multiple of \code{input} whose
|
|
leading coefficient is the greatest common divisor of the leading
|
|
coefficient and the modulus of \code{input}.
|
|
|
|
void nmod_poly_make_monic(nmod_poly_t output, const nmod_poly_t input)
|
|
|
|
Sets \code{output} to be the scalar multiple of \code{input} with leading
|
|
coefficient one, if such a polynomial exists. If \code{input} is zero
|
|
an exception is raised. If the leading coefficient of \code{input} is not
|
|
invertible, \code{output} is set to the multiple of \code{input} whose
|
|
leading coefficient is the greatest common divisor of the leading
|
|
coefficient and the modulus of \code{input}.
|
|
|
|
*******************************************************************************
|
|
|
|
Bit packing and unpacking
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_bit_pack(mp_ptr res, mp_srcptr poly, slong len,
|
|
mp_bitcnt_t bits)
|
|
|
|
Packs \code{len} coefficients of \code{poly} into fields of the given
|
|
number of bits in the large integer \code{res}, i.e.\ evaluates
|
|
\code{poly} at \code{2^bits} and store the result in \code{res}.
|
|
Assumes \code{len > 0} and \code{bits > 0}. Also assumes that no
|
|
coefficient of \code{poly} is bigger than \code{bits/2} bits. We
|
|
also assume \code{bits < 3 * FLINT_BITS}.
|
|
|
|
void _nmod_poly_bit_unpack(mp_ptr res, slong len,
|
|
mp_srcptr mpn, ulong bits, nmod_t mod)
|
|
|
|
Unpacks \code{len} coefficients stored in the big integer \code{mpn}
|
|
in bit fields of the given number of bits, reduces them modulo the
|
|
given modulus, then stores them in the polynomial \code{res}.
|
|
We assume \code{len > 0} and \code{3 * FLINT_BITS > bits > 0}.
|
|
There are no restrictions on the size of the actual coefficients as
|
|
stored within the bitfields.
|
|
|
|
void nmod_poly_bit_pack(fmpz_t f, const nmod_poly_t poly, mp_bitcnt_t bit_size)
|
|
|
|
Packs \code{poly} into bitfields of size \code{bit_size}, writing the
|
|
result to \code{f}.
|
|
|
|
void nmod_poly_bit_unpack(nmod_poly_t poly, const fmpz_t f,
|
|
mp_bitcnt_t bit_size)
|
|
|
|
Unpacks the polynomial from fields of size \code{bit_size} as
|
|
represented by the integer \code{f}.
|
|
|
|
|
|
void _nmod_poly_KS2_pack1(mp_ptr res, mp_srcptr op, slong n, slong s,
|
|
ulong b, ulong k, slong r)
|
|
|
|
Same as \code{_nmod_poly_KS2_pack}, but requires \code{b <= FLINT_BITS}.
|
|
|
|
void _nmod_poly_KS2_pack(mp_ptr res, mp_srcptr op, slong n, slong s,
|
|
ulong b, ulong k, slong r)
|
|
|
|
Bit packing routine used by KS2 and KS4 multiplication.
|
|
|
|
void _nmod_poly_KS2_unpack1(mp_ptr res, mp_srcptr op, slong n, ulong b,
|
|
ulong k)
|
|
|
|
Same as \code{_nmod_poly_KS2_unpack}, but requires \code{b <= FLINT_BITS}
|
|
(i.e. writes one word per coefficient).
|
|
|
|
void _nmod_poly_KS2_unpack2(mp_ptr res, mp_srcptr op, slong n, ulong b,
|
|
ulong k)
|
|
|
|
Same as \code{_nmod_poly_KS2_unpack}, but requires
|
|
\code{FLINT_BITS < b <= 2 * FLINT_BITS} (i.e. writes two words per
|
|
coefficient).
|
|
|
|
void _nmod_poly_KS2_unpack3(mp_ptr res, mp_srcptr op, slong n, ulong b,
|
|
ulong k)
|
|
|
|
Same as \code{_nmod_poly_KS2_unpack}, but requires
|
|
\code{2 * FLINT_BITS < b < 3 * FLINT_BITS} (i.e. writes three words per
|
|
coefficient).
|
|
|
|
void _nmod_poly_KS2_unpack(mp_ptr res, mp_srcptr op, slong n, ulong b,
|
|
ulong k)
|
|
|
|
Bit unpacking code used by KS2 and KS4 multiplication.
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
KS2/KS4 Reduction
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_KS2_reduce(mp_ptr res, slong s, mp_srcptr op, slong n, ulong w,
|
|
nmod_t mod)
|
|
|
|
Reduction code used by KS2 and KS4 multiplication.
|
|
|
|
void _nmod_poly_KS2_recover_reduce1(mp_ptr res, slong s, mp_srcptr op1,
|
|
mp_srcptr op2, slong n, ulong b, nmod_t mod)
|
|
|
|
Same as \code{_nmod_poly_KS2_recover_reduce}, but requires
|
|
\code{0 < 2 * b <= FLINT_BITS}.
|
|
|
|
void _nmod_poly_KS2_recover_reduce2(mp_ptr res, slong s, mp_srcptr op1,
|
|
mp_srcptr op2, slong n, ulong b, nmod_t mod)
|
|
|
|
Same as \code{_nmod_poly_KS2_recover_reduce}, but requires
|
|
\code{FLINT_BITS < 2 * b < 2*FLINT_BITS}.
|
|
|
|
void _nmod_poly_KS2_recover_reduce2b(mp_ptr res, slong s, mp_srcptr op1,
|
|
mp_srcptr op2, slong n, ulong b, nmod_t mod)
|
|
|
|
Same as \code{_nmod_poly_KS2_recover_reduce}, but requires
|
|
\code{b == FLINT_BITS}.
|
|
|
|
void _nmod_poly_KS2_recover_reduce3(mp_ptr res, slong s, mp_srcptr op1,
|
|
mp_srcptr op2, slong n, ulong b, nmod_t mod)
|
|
|
|
Same as \code{_nmod_poly_KS2_recover_reduce}, but requires
|
|
\code{2 * FLINT_BITS < 2 * b <= 3 * FLINT_BITS}.
|
|
|
|
void _nmod_poly_KS2_recover_reduce(mp_ptr res, slong s, mp_srcptr op1,
|
|
mp_srcptr op2, slong n, ulong b, nmod_t mod)
|
|
|
|
Reduction code used by KS4 multiplication.
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
Multiplication
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_mul_classical(mp_ptr res, mp_srcptr poly1,
|
|
slong len1, mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Sets \code{(res, len1 + len2 - 1)} to the product of \code{(poly1, len1)}
|
|
and \code{(poly2, len2)}. Assumes \code{len1 >= len2 > 0}. Aliasing of
|
|
inputs and output is not permitted.
|
|
|
|
void nmod_poly_mul_classical(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2)
|
|
|
|
Sets \code{res} to the product of \code{poly1} and \code{poly2}.
|
|
|
|
void _nmod_poly_mullow_classical(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, slong trunc, nmod_t mod)
|
|
|
|
Sets \code{res} to the lower \code{trunc} coefficients of the product of
|
|
\code{(poly1, len1)} and \code{(poly2, len2)}. Assumes that
|
|
\code{len1 >= len2 > 0} and \code{trunc > 0}. Aliasing of inputs and
|
|
output is not permitted.
|
|
|
|
void nmod_poly_mullow_classical(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, slong trunc)
|
|
|
|
Sets \code{res} to the lower \code{trunc} coefficients of the product
|
|
of \code{poly1} and \code{poly2}.
|
|
|
|
void _nmod_poly_mulhigh_classical(mp_ptr res, mp_srcptr poly1,
|
|
slong len1, mp_srcptr poly2, slong len2, slong start, nmod_t mod)
|
|
|
|
Computes the product of \code{(poly1, len1)} and \code{(poly2, len2)}
|
|
and writes the coefficients from \code{start} onwards into the high
|
|
coefficients of \code{res}, the remaining coefficients being arbitrary
|
|
but reduced. Assumes that \code{len1 >= len2 > 0}. Aliasing of inputs
|
|
and output is not permitted.
|
|
|
|
void nmod_poly_mulhigh_classical(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, slong start)
|
|
|
|
Computes the product of \code{poly1} and \code{poly2} and writes the
|
|
coefficients from \code{start} onwards into the high coefficients of
|
|
\code{res}, the remaining coefficients being arbitrary but reduced.
|
|
|
|
void _nmod_poly_mul_KS(mp_ptr out, mp_srcptr in1, slong len1,
|
|
mp_srcptr in2, slong len2, mp_bitcnt_t bits, nmod_t mod)
|
|
|
|
Sets \code{res} to the product of \code{in1} and \code{in2}
|
|
assuming the output coefficients are at most the given number of
|
|
bits wide. If \code{bits} is set to $0$ an appropriate value is
|
|
computed automatically. Assumes that \code{len1 >= len2 > 0}.
|
|
|
|
void nmod_poly_mul_KS(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, mp_bitcnt_t bits)
|
|
|
|
Sets \code{res} to the product of \code{poly1} and \code{poly2}
|
|
assuming the output coefficients are at most the given number of
|
|
bits wide. If \code{bits} is set to $0$ an appropriate value
|
|
is computed automatically.
|
|
|
|
void _nmod_poly_mul_KS2(mp_ptr res, mp_srcptr op1, slong n1,
|
|
mp_srcptr op2, slong n2, nmod_t mod)
|
|
|
|
Sets \code{res} to the product of \code{op1} and \code{op2}.
|
|
Assumes that \code{len1 >= len2 > 0}.
|
|
|
|
void nmod_poly_mul_KS2(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2)
|
|
|
|
Sets \code{res} to the product of \code{poly1} and \code{poly2}.
|
|
|
|
void _nmod_poly_mul_KS4(mp_ptr res, mp_srcptr op1, slong n1,
|
|
mp_srcptr op2, slong n2, nmod_t mod)
|
|
|
|
Sets \code{res} to the product of \code{op1} and \code{op2}.
|
|
Assumes that \code{len1 >= len2 > 0}.
|
|
|
|
void nmod_poly_mul_KS4(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2)
|
|
|
|
Sets \code{res} to the product of \code{poly1} and \code{poly2}.
|
|
|
|
void _nmod_poly_mullow_KS(mp_ptr out, mp_srcptr in1, slong len1,
|
|
mp_srcptr in2, slong len2, mp_bitcnt_t bits, slong n, nmod_t mod)
|
|
|
|
Sets \code{out} to the low $n$ coefficients of \code{in1} of length
|
|
\code{len1} times \code{in2} of length \code{len2}. The output must have
|
|
space for \code{n} coefficients. We assume that \code{len1 >= len2 > 0}
|
|
and that \code{0 < n <= len1 + len2 - 1}.
|
|
|
|
void nmod_poly_mullow_KS(nmod_poly_t res, const nmod_poly_t poly1,
|
|
const nmod_poly_t poly2, mp_bitcnt_t bits, slong n)
|
|
|
|
Set \code{res} to the low $n$ coefficients of \code{in1} of length
|
|
\code{len1} times \code{in2} of length \code{len2}.
|
|
|
|
void _nmod_poly_mul(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Sets \code{res} to the product of \code{poly1} of length \code{len1}
|
|
and \code{poly2} of length \code{len2}. Assumes \code{len1 >= len2 > 0}.
|
|
No aliasing is permitted between the inputs and the output.
|
|
|
|
void nmod_poly_mul(nmod_poly_t res,
|
|
const nmod_poly_t poly, const nmod_poly_t poly2)
|
|
|
|
Sets \code{res} to the product of \code{poly1} and \code{poly2}.
|
|
|
|
void _nmod_poly_mullow(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, slong n, nmod_t mod)
|
|
|
|
Sets \code{res} to the first \code{n} coefficients of the
|
|
product of \code{poly1} of length \code{len1} and \code{poly2} of
|
|
length \code{len2}. It is assumed that \code{0 < n <= len1 + len2 - 1}
|
|
and that \code{len1 >= len2 > 0}. No aliasing of inputs and output
|
|
is permitted.
|
|
|
|
void nmod_poly_mullow(nmod_poly_t res, const nmod_poly_t poly1,
|
|
const nmod_poly_t poly2, slong trunc)
|
|
|
|
Sets \code{res} to the first \code{trunc} coefficients of the
|
|
product of \code{poly1} and \code{poly2}.
|
|
|
|
void _nmod_poly_mulhigh(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, slong n, nmod_t mod)
|
|
|
|
Sets all but the low $n$ coefficients of \code{res} to the
|
|
corresponding coefficients of the product of \code{poly1} of length
|
|
\code{len1} and \code{poly2} of length \code{len2}, the other
|
|
coefficients being arbitrary. It is assumed that
|
|
\code{len1 >= len2 > 0} and that \code{0 < n <= len1 + len2 - 1}.
|
|
Aliasing of inputs and output is not permitted.
|
|
|
|
void nmod_poly_mulhigh(nmod_poly_t res, const nmod_poly_t poly1,
|
|
const nmod_poly_t poly2, slong n)
|
|
|
|
Sets all but the low $n$ coefficients of \code{res} to the
|
|
corresponding coefficients of the product of \code{poly1} and
|
|
\code{poly2}, the remaining coefficients being arbitrary.
|
|
|
|
void _nmod_poly_mulmod(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, mp_srcptr f,
|
|
slong lenf, nmod_t mod)
|
|
|
|
Sets \code{res} to the remainder of the product of \code{poly1} and
|
|
\code{poly2} upon polynomial division by \code{f}.
|
|
|
|
It is required that \code{len1 + len2 - lenf > 0}, which is equivalent
|
|
to requiring that the result will actually be reduced. Otherwise, simply
|
|
use \code{_nmod_poly_mul} instead.
|
|
|
|
Aliasing of \code{f} and \code{res} is not permitted.
|
|
|
|
void nmod_poly_mulmod(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, const nmod_poly_t f)
|
|
|
|
Sets \code{res} to the remainder of the product of \code{poly1} and
|
|
\code{poly2} upon polynomial division by \code{f}.
|
|
|
|
void _nmod_poly_mulmod_preinv(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, mp_srcptr f,
|
|
slong lenf, mp_srcptr finv, slong lenfinv, nmod_t mod)
|
|
|
|
Sets \code{res} to the remainder of the product of \code{poly1} and
|
|
\code{poly2} upon polynomial division by \code{f}.
|
|
|
|
It is required that \code{finv} is the inverse of the reverse of \code{f}
|
|
mod \code{x^lenf}. It is required that \code{len1 + len2 - lenf > 0},
|
|
which is equivalent to requiring that the result will actually be reduced.
|
|
It is required that \code{len1 < lenf} and \code{len2 < lenf}.
|
|
Otherwise, simply use \code{_nmod_poly_mul} instead.
|
|
|
|
Aliasing of \code{f} or \code{finv} and \code{res} is not permitted.
|
|
|
|
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)
|
|
|
|
Sets \code{res} to the remainder of the product of \code{poly1} and
|
|
\code{poly2} upon polynomial division by \code{f}. \code{finv} is the
|
|
inverse of the reverse of \code{f}. It is required that \code{poly1} and
|
|
\code{poly2} are reduced modulo \code{f}.
|
|
|
|
*******************************************************************************
|
|
|
|
Powering
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_pow_binexp(mp_ptr res,
|
|
mp_srcptr poly, slong len, ulong e, nmod_t mod)
|
|
|
|
Raises \code{poly} of length \code{len} to the power \code{e} and sets
|
|
\code{res} to the result. We require that \code{res} has enough space
|
|
for \code{(len - 1)*e + 1} coefficients. Assumes that \code{len > 0},
|
|
\code{e > 1}. Aliasing is not permitted. Uses the binary exponentiation
|
|
method.
|
|
|
|
void nmod_poly_pow_binexp(nmod_poly_t res, const nmod_poly_t poly, ulong e)
|
|
|
|
Raises \code{poly} to the power \code{e} and sets \code{res} to the
|
|
result. Uses the binary exponentiation method.
|
|
|
|
void _nmod_poly_pow(mp_ptr res,
|
|
mp_srcptr poly, slong len, ulong e, nmod_t mod)
|
|
|
|
Raises \code{poly} of length \code{len} to the power \code{e} and sets
|
|
\code{res} to the result. We require that \code{res} has enough space
|
|
for \code{(len - 1)*e + 1} coefficients. Assumes that \code{len > 0},
|
|
\code{e > 1}. Aliasing is not permitted.
|
|
|
|
void nmod_poly_pow(nmod_poly_t res, const nmod_poly_t poly, ulong e)
|
|
|
|
Raises \code{poly} to the power \code{e} and sets \code{res} to the
|
|
result.
|
|
|
|
void _nmod_poly_pow_trunc_binexp(mp_ptr res, mp_srcptr poly,
|
|
ulong e, slong trunc, nmod_t mod)
|
|
|
|
Sets \code{res} to the low \code{trunc} coefficients of \code{poly}
|
|
(assumed to be zero padded if necessary to length \code{trunc}) to
|
|
the power \code{e}. This is equivalent to doing a powering followed
|
|
by a truncation. We require that \code{res} has enough space for
|
|
\code{trunc} coefficients, that \code{trunc > 0} and that
|
|
\code{e > 1}. Aliasing is not permitted. Uses the binary
|
|
exponentiation method.
|
|
|
|
void nmod_poly_pow_trunc_binexp(nmod_poly_t res,
|
|
const nmod_poly_t poly, ulong e, slong trunc)
|
|
|
|
Sets \code{res} to the low \code{trunc} coefficients of \code{poly}
|
|
to the power \code{e}. This is equivalent to doing a powering
|
|
followed by a truncation. Uses the binary exponentiation method.
|
|
|
|
void _nmod_poly_pow_trunc(mp_ptr res, mp_srcptr poly,
|
|
ulong e, slong trunc, nmod_t mod)
|
|
|
|
Sets \code{res} to the low \code{trunc} coefficients of \code{poly}
|
|
(assumed to be zero padded if necessary to length \code{trunc}) to
|
|
the power \code{e}. This is equivalent to doing a powering followed
|
|
by a truncation. We require that \code{res} has enough space for
|
|
\code{trunc} coefficients, that \code{trunc > 0} and that
|
|
\code{e > 1}. Aliasing is not permitted.
|
|
|
|
void nmod_poly_pow_trunc(nmod_poly_t res,
|
|
const nmod_poly_t poly, ulong e, slong trunc)
|
|
|
|
Sets \code{res} to the low \code{trunc} coefficients of \code{poly}
|
|
to the power \code{e}. This is equivalent to doing a powering
|
|
followed by a truncation.
|
|
|
|
void _nmod_poly_powmod_ui_binexp(mp_ptr res, mp_srcptr poly,
|
|
ulong e, mp_srcptr f,
|
|
slong lenf, nmod_t mod)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e > 0}.
|
|
|
|
We require \code{lenf > 1}. It is assumed that \code{poly} is already
|
|
reduced modulo \code{f} and zero-padded as necessary to have length
|
|
exactly \code{lenf - 1}. The output \code{res} must have room for
|
|
\code{lenf - 1} coefficients.
|
|
|
|
void nmod_poly_powmod_ui_binexp(nmod_poly_t res,
|
|
const nmod_poly_t poly, ulong e,
|
|
const nmod_poly_t f)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e >= 0}.
|
|
|
|
void
|
|
_nmod_poly_powmod_ui_binexp_preinv (mp_ptr res, mp_srcptr poly,
|
|
ulong e, mp_srcptr f, slong lenf,
|
|
mp_srcptr finv, slong lenfinv, nmod_t mod)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e > 0}.
|
|
We require \code{finv} to be the inverse of the reverse of \code{f}.
|
|
|
|
We require \code{lenf > 1}. It is assumed that \code{poly} is already
|
|
reduced modulo \code{f} and zero-padded as necessary to have length
|
|
exactly \code{lenf - 1}. The output \code{res} must have room for
|
|
\code{lenf - 1} coefficients.
|
|
|
|
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)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e >= 0}.
|
|
We require \code{finv} to be the inverse of the reverse of \code{f}.
|
|
|
|
void
|
|
_nmod_poly_powmod_x_ui_preinv (mp_ptr res, ulong e, mp_srcptr f, slong lenf,
|
|
mp_srcptr finv, slong lenfinv, nmod_t mod)
|
|
|
|
Sets \code{res} to \code{x} raised to the power \code{e} modulo \code{f},
|
|
using sliding window exponentiation. We require \code{e > 0}.
|
|
We require \code{finv} to be the inverse of the reverse of \code{f}.
|
|
|
|
We require \code{lenf > 2}. The output \code{res} must have room for
|
|
\code{lenf - 1} coefficients.
|
|
|
|
void
|
|
nmod_poly_powmod_x_ui_preinv(nmod_poly_t res, ulong e, const nmod_poly_t f,
|
|
const nmod_poly_t finv)
|
|
|
|
Sets \code{res} to \code{x} raised to the power \code{e}
|
|
modulo \code{f}, using sliding window exponentiation. We require
|
|
\code{e >= 0}. We require \code{finv} to be the inverse of the reverse of
|
|
\code{f}.
|
|
|
|
void _nmod_poly_powmod_mpz_binexp(mp_ptr res, mp_srcptr poly,
|
|
mpz_srcptr e, mp_srcptr f,
|
|
slong lenf, nmod_t mod)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e > 0}.
|
|
|
|
We require \code{lenf > 1}. It is assumed that \code{poly} is already
|
|
reduced modulo \code{f} and zero-padded as necessary to have length
|
|
exactly \code{lenf - 1}. The output \code{res} must have room for
|
|
\code{lenf - 1} coefficients.
|
|
|
|
void nmod_poly_powmod_mpz_binexp(nmod_poly_t res,
|
|
const nmod_poly_t poly, mpz_srcptr e,
|
|
const nmod_poly_t f)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e >= 0}.
|
|
|
|
void
|
|
_nmod_poly_powmod_mpz_binexp_preinv (mp_ptr res, mp_srcptr poly,
|
|
mpz_srcptr e, mp_srcptr f, slong lenf,
|
|
mp_srcptr finv, slong lenfinv, nmod_t mod)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e > 0}.
|
|
We require \code{finv} to be the inverse of the reverse of \code{f}.
|
|
|
|
We require \code{lenf > 1}. It is assumed that \code{poly} is already
|
|
reduced modulo \code{f} and zero-padded as necessary to have length
|
|
exactly \code{lenf - 1}. The output \code{res} must have room for
|
|
\code{lenf - 1} coefficients.
|
|
|
|
void
|
|
nmod_poly_powmod_mpz_binexp_preinv(nmod_poly_t res,
|
|
const nmod_poly_t poly, mpz_srcptr e,
|
|
const nmod_poly_t f, const nmod_poly_t finv)
|
|
|
|
Sets \code{res} to \code{poly} raised to the power \code{e}
|
|
modulo \code{f}, using binary exponentiation. We require \code{e >= 0}.
|
|
We require \code{finv} to be the inverse of the reverse of \code{f}.
|
|
|
|
*******************************************************************************
|
|
|
|
Division
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_divrem_basecase(mp_ptr Q, mp_ptr R, mp_ptr W,
|
|
mp_srcptr A, slong A_len, mp_srcptr B, slong B_len, nmod_t mod)
|
|
|
|
Finds $Q$ and $R$ such that $A = B Q + R$ with $\len(R) < \len(B)$.
|
|
If $\len(B) = 0$ an exception is raised. We require that \code{W}
|
|
is temporary space of \code{NMOD_DIVREM_BC_ITCH(A_len, B_len, mod)}
|
|
coefficients.
|
|
|
|
void nmod_poly_divrem_basecase(nmod_poly_t Q,
|
|
nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Finds $Q$ and $R$ such that $A = B Q + R$ with $\len(R) < \len(B)$.
|
|
If $\len(B) = 0$ an exception is raised.
|
|
|
|
void _nmod_poly_div_basecase(mp_ptr Q, mp_ptr W, mp_srcptr A, slong A_len,
|
|
mp_srcptr B, slong B_len, nmod_t mod);
|
|
|
|
Notionally finds polynomials $Q$ and $R$ such that $A = B Q + R$ with
|
|
$\len(R) < \len(B)$, but returns only \code{Q}. If $\len(B) = 0$ an
|
|
exception is raised. We require that \code{W} is temporary space of
|
|
\code{NMOD_DIV_BC_ITCH(A_len, B_len, mod)} coefficients.
|
|
|
|
void nmod_poly_div_basecase(nmod_poly_t Q, const nmod_poly_t A,
|
|
const nmod_poly_t B);
|
|
|
|
Notionally finds polynomials $Q$ and $R$ such that $A = B Q + R$ with
|
|
$\len(R) < \len(B)$, but returns only \code{Q}. If $\len(B) = 0$ an
|
|
exception is raised.
|
|
|
|
void _nmod_poly_divrem_divconquer_recursive(mp_ptr Q, mp_ptr BQ, mp_ptr W,
|
|
mp_ptr V, mp_srcptr A, mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R)$ less than
|
|
\code{lenB}, where \code{A} is of length \code{2 * lenB - 1} and \code{B}
|
|
is of length \code{lenB}. Sets \code{BQ} to the low \code{lenB - 1}
|
|
coefficients of \code{B * Q}. We require that \code{Q} have space for
|
|
\code{lenB} coefficients, that \code{W} be temporary space of size
|
|
\code{lenB - 1} and \code{V} be temporary space for a number of
|
|
coefficients computed by \code{NMOD_DIVREM_DC_ITCH(lenB, mod)}.
|
|
|
|
void _nmod_poly_divrem_divconquer(mp_ptr Q, mp_ptr R,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R)$ less than
|
|
\code{lenB}, where \code{A} is of length \code{lenA} and \code{B} is of
|
|
length \code{lenB}. We require that \code{Q} have space for
|
|
\code{lenA - lenB + 1} coefficients.
|
|
|
|
void nmod_poly_divrem_divconquer(nmod_poly_t Q, nmod_poly_t R,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R) < \len(B)$.
|
|
|
|
void _nmod_poly_divrem_q0(mp_ptr Q, mp_ptr R,
|
|
mp_srcptr A, mp_srcptr B, slong lenA, nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R) < \len(B)$,
|
|
where $\len(A) = \len(B) > 0$.
|
|
|
|
Requires that $Q$ and $R$ have space for $1$ and $\len(B) - 1$
|
|
coefficients, respectively.
|
|
|
|
Does not support aliasing or zero-padding.
|
|
|
|
void _nmod_poly_divrem_q1(mp_ptr Q, mp_ptr R,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB,
|
|
nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R) < \len(B)$,
|
|
where $\len(A) = \len(B) + 1 \geq \len(B) > 0$.
|
|
|
|
Requires that $Q$ and $R$ have space for $\len(A) - \len(B) + 1$ and
|
|
$\len(B) - 1$ coefficients, respectively.
|
|
|
|
Does not support aliasing or zero-padding.
|
|
|
|
void _nmod_poly_divrem(mp_ptr Q, mp_ptr R,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R)$ less than
|
|
\code{lenB}, where \code{A} is of length \code{lenA} and \code{B} is of
|
|
length \code{lenB}. We require that \code{Q} have space for
|
|
\code{lenA - lenB + 1} coefficients.
|
|
|
|
void nmod_poly_divrem(nmod_poly_t Q, nmod_poly_t R,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R) < \len(B)$.
|
|
|
|
void _nmod_poly_div_divconquer_recursive(mp_ptr Q, mp_ptr W, mp_ptr V,
|
|
mp_srcptr A, mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R)$ less than
|
|
\code{lenB}, where \code{A} is of length \code{2 * lenB - 1} and \code{B}
|
|
is of length \code{lenB}. We require that \code{Q} have space for
|
|
\code{lenB} coefficients and that \code{W} be temporary space of size
|
|
\code{lenB - 1} and \code{V} be temporary space for a number of
|
|
coefficients computed by \code{NMOD_DIV_DC_ITCH(lenB, mod)}.
|
|
|
|
void _nmod_poly_div_divconquer(mp_ptr Q, mp_srcptr A, slong lenA,
|
|
mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Notionally computes polynomials $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R)$ less than \code{lenB}, where \code{A} is of length \code{lenA}
|
|
and \code{B} is of length \code{lenB}, but returns only \code{Q}. We
|
|
require that \code{Q} have space for \code{lenA - lenB + 1} coefficients.
|
|
|
|
void nmod_poly_div_divconquer(nmod_poly_t Q,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Notionally computes $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R) < \len(B)$, but returns only $Q$.
|
|
|
|
void _nmod_poly_div(mp_ptr Q, mp_srcptr A, slong lenA,
|
|
mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Notionally computes polynomials $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R)$ less than \code{lenB}, where \code{A} is of length \code{lenA}
|
|
and \code{B} is of length \code{lenB}, but returns only \code{Q}. We
|
|
require that \code{Q} have space for \code{lenA - lenB + 1} coefficients.
|
|
|
|
|
|
void nmod_poly_div(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes the quotient $Q$ on polynomial division of $A$ and $B$.
|
|
|
|
void _nmod_poly_rem_basecase(mp_ptr R, mp_ptr W, mp_srcptr A, slong lenA,
|
|
mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
void nmod_poly_rem_basecase(nmod_poly_t R,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
void _nmod_poly_rem_q1(mp_ptr R,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB,
|
|
nmod_t mod)
|
|
|
|
Notationally, computes $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R) < \len(B)$, where $\len(A) = \len(B) + 1 \geq \len(B) > 0$,
|
|
but returns only the remainder.
|
|
|
|
Requires that $R$ has space for $\len(B) - 1$ coefficients,
|
|
respectively.
|
|
|
|
Does not support aliasing or zero-padding.
|
|
|
|
void _nmod_poly_rem(mp_ptr R, mp_srcptr A, slong lenA,
|
|
mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes the remainder $R$ on polynomial division of $A$ by $B$.
|
|
|
|
void nmod_poly_rem(nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes the remainder $R$ on polynomial division of $A$ by $B$.
|
|
|
|
void _nmod_poly_inv_series_basecase(mp_ptr Qinv,
|
|
mp_srcptr Q, slong n, nmod_t mod)
|
|
|
|
Given \code{Q} of length \code{n} whose leading coefficient is invertible
|
|
modulo the given modulus, finds a polynomial \code{Qinv} of length \code{n}
|
|
such that the top \code{n} coefficients of the product \code{Q * Qinv} is
|
|
$x^{n - 1}$. Requires that \code{n > 0}. This function can be viewed as
|
|
inverting a power series.
|
|
|
|
void nmod_poly_inv_series_basecase(nmod_poly_t Qinv,
|
|
const nmod_poly_t Q, slong n)
|
|
|
|
Given \code{Q} of length at least \code{n} find \code{Qinv} of length
|
|
\code{n} such that the top \code{n} coefficients of the product
|
|
\code{Q * Qinv} is $x^{n - 1}$. An exception is raised if \code{n = 0}
|
|
or if the length of \code{Q} is less than \code{n}. The leading
|
|
coefficient of \code{Q} must be invertible modulo the modulus of
|
|
\code{Q}. This function can be viewed as inverting a power series.
|
|
|
|
void
|
|
_nmod_poly_inv_series_newton(mp_ptr Qinv, mp_srcptr Q, slong n, nmod_t mod)
|
|
|
|
Given \code{Q} of length \code{n} whose constant coefficient is invertible
|
|
modulo the given modulus, find a polynomial \code{Qinv} of length \code{n}
|
|
such that \code{Q * Qinv} is \code{1} modulo $x^n$. Requires \code{n > 0}.
|
|
This function can be viewed as inverting a power series via Newton
|
|
iteration.
|
|
|
|
void
|
|
nmod_poly_inv_series_newton(nmod_poly_t Qinv, const nmod_poly_t Q, slong n)
|
|
|
|
Given \code{Q} find \code{Qinv} such that \code{Q * Qinv} is \code{1}
|
|
modulo $x^n$. The constant coefficient of \code{Q} must be invertible
|
|
modulo the modulus of \code{Q}. An exception is raised if this is not
|
|
the case or if \code{n = 0}. This function can be viewed as inverting
|
|
a power series via Newton iteration.
|
|
|
|
void _nmod_poly_inv_series(mp_ptr Qinv, mp_srcptr Q, slong n, nmod_t mod)
|
|
|
|
Given \code{Q} of length \code{n} whose constant coefficient is invertible
|
|
modulo the given modulus, find a polynomial \code{Qinv} of length \code{n}
|
|
such that \code{Q * Qinv} is \code{1} modulo $x^n$. Requires \code{n > 0}.
|
|
This function can be viewed as inverting a power series.
|
|
|
|
void nmod_poly_inv_series(nmod_poly_t Qinv, const nmod_poly_t Q, slong n)
|
|
|
|
Given \code{Q} find \code{Qinv} such that \code{Q * Qinv} is \code{1}
|
|
modulo $x^n$. The constant coefficient of \code{Q} must be invertible
|
|
modulo the modulus of \code{Q}. An exception is raised if this is not
|
|
the case or if \code{n = 0}. This function can be viewed as inverting
|
|
a power series.
|
|
|
|
void _nmod_poly_div_series(mp_ptr Q, mp_srcptr A, mp_srcptr B,
|
|
slong n, nmod_t mod)
|
|
|
|
Given polynomials \code{A} and \code{B} of length \code{n}, finds the
|
|
polynomial \code{Q} of length \code{n} such that \code{Q * B = A}
|
|
modulo $x^n$. We assume \code{n > 0} and that the constant coefficient
|
|
of \code{B} is invertible modulo the given modulus. The polynomial
|
|
\code{Q} must have space for \code{n} coefficients.
|
|
|
|
void nmod_poly_div_series(nmod_poly_t Q, const nmod_poly_t A,
|
|
const nmod_poly_t B, slong n)
|
|
|
|
Given polynomials \code{A} and \code{B} considered modulo \code{n},
|
|
finds the polynomial \code{Q} of length at most \code{n} such that
|
|
\code{Q * B = A} modulo $x^n$. We assume \code{n > 0} and that the
|
|
constant coefficient of \code{B} is invertible modulo the modulus.
|
|
An exception is raised if \code{n == 0} or the constant coefficient
|
|
of \code{B} is zero.
|
|
|
|
void _nmod_poly_div_newton(mp_ptr Q, mp_srcptr A, slong Alen,
|
|
mp_srcptr B, slong Blen, nmod_t mod)
|
|
|
|
Notionally computes polynomials $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R)$ less than \code{lenB}, where \code{A} is of length \code{lenA}
|
|
and \code{B} is of length \code{lenB}, but return only $Q$.
|
|
|
|
We require that $Q$ have space for \code{lenA - lenB + 1} coefficients
|
|
and assume that the leading coefficient of $B$ is a unit.
|
|
|
|
The algorithm used is to reverse the polynomials and divide the
|
|
resulting power series, then reverse the result.
|
|
|
|
void nmod_poly_div_newton(nmod_poly_t Q, const nmod_poly_t A,
|
|
const nmod_poly_t B)
|
|
|
|
Notionally computes $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R) < \len(B)$, but returns only $Q$.
|
|
|
|
We assume that the leading coefficient of $B$ is a unit.
|
|
|
|
The algorithm used is to reverse the polynomials and divide the
|
|
resulting power series, then reverse the result.
|
|
|
|
void _nmod_poly_div_newton_n_preinv (mp_ptr Q, mp_srcptr A, slong lenA,
|
|
mp_srcptr B, slong lenB, mp_srcptr Binv, slong lenBinv, nmod_t mod)
|
|
|
|
Notionally computes polynomials $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R)$ less than \code{lenB}, where \code{A} is of length \code{lenA}
|
|
and \code{B} is of length \code{lenB}, but return only $Q$.
|
|
|
|
We require that $Q$ have space for \code{lenA - lenB + 1} coefficients
|
|
and assume that the leading coefficient of $B$ is a unit. Furthermore, we
|
|
assume that $Binv$ is the inverse of the reverse of $B$ mod $x^{\len(B)}$.
|
|
|
|
The algorithm used is to reverse the polynomials and divide the
|
|
resulting power series, then reverse the result.
|
|
|
|
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)
|
|
|
|
Notionally computes $Q$ and $R$ such that $A = BQ + R$ with
|
|
$\len(R) < \len(B)$, but returns only $Q$.
|
|
|
|
We assume that the leading coefficient of $B$ is a unit and that $Binv$ is
|
|
the inverse of the reverse of $B$ mod $x^{\len(B)}$.
|
|
|
|
It is required that the length of $A$ is less than or equal to
|
|
2*the length of $B$ - 2.
|
|
|
|
The algorithm used is to reverse the polynomials and divide the
|
|
resulting power series, then reverse the result.
|
|
|
|
void _nmod_poly_divrem_newton(mp_ptr Q, mp_ptr R, mp_srcptr A, slong Alen,
|
|
mp_srcptr B, slong Blen, nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R)$ less than
|
|
\code{lenB}, where $A$ is of length \code{lenA} and $B$ is of length
|
|
\code{lenB}. We require that $Q$ have space for \code{lenA - lenB + 1}
|
|
coefficients. The algorithm used is to call \code{div_newton()} and then
|
|
multiply out and compute the remainder.
|
|
|
|
void nmod_poly_divrem_newton(nmod_poly_t Q, nmod_poly_t R,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R) < \len(B)$.
|
|
The algorithm used is to call \code{div_newton()} and then multiply out
|
|
and compute the remainder.
|
|
|
|
void _nmod_poly_divrem_newton_n_preinv (mp_ptr Q, mp_ptr R, mp_srcptr A,
|
|
slong lenA, mp_srcptr B, slong lenB, mp_srcptr Binv, slong lenBinv, nmod_t mod)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R)$ less than
|
|
\code{lenB}, where $A$ is of length \code{lenA} and $B$ is of length
|
|
\code{lenB}. We require that $Q$ have space for \code{lenA - lenB + 1}
|
|
coefficients. Furthermore, we assume that $Binv$ is the inverse of the
|
|
reverse of $B$ mod $x^{\len(B)}$. The algorithm used is to call
|
|
\code{div_newton_n_preinv()} and then multiply out and compute
|
|
the remainder.
|
|
|
|
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)
|
|
|
|
Computes $Q$ and $R$ such that $A = BQ + R$ with $\len(R) < \len(B)$.
|
|
We assume $Binv$ is the inverse of the reverse of $B$ mod $x^{\len(B)}$.
|
|
|
|
It is required that the length of $A$ is less than or equal to
|
|
2*the length of $B$ - 2.
|
|
|
|
The algorithm used is to call \code{div_newton_n()} and then multiply out
|
|
and compute the remainder.
|
|
|
|
mp_limb_t _nmod_poly_div_root(mp_ptr Q, mp_srcptr A, slong len,
|
|
mp_limb_t c, nmod_t mod)
|
|
|
|
Sets \code{(Q, len-1)} to the quotient of \code{(A, len)} on division
|
|
by $(x - c)$, and returns the remainder, equal to the value of $A$
|
|
evaluated at $c$. $A$ and $Q$ are allowed to be the same, but may
|
|
not overlap partially in any other way.
|
|
|
|
mp_limb_t nmod_poly_div_root(nmod_poly_t Q, const nmod_poly_t A, mp_limb_t c)
|
|
|
|
Sets $Q$ to the quotient of $A$ on division by $(x - c)$, and returns
|
|
the remainder, equal to the value of $A$ evaluated at $c$.
|
|
|
|
*******************************************************************************
|
|
|
|
Derivative and integral
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_derivative(mp_ptr x_prime, mp_srcptr x, slong len, nmod_t mod)
|
|
|
|
Sets the first \code{len - 1} coefficients of \code{x_prime} to the
|
|
derivative of \code{x} which is assumed to be of length \code{len}.
|
|
It is assumed that \code{len > 0}.
|
|
|
|
void nmod_poly_derivative(nmod_poly_t x_prime, const nmod_poly_t x)
|
|
|
|
Sets \code{x_prime} to the derivative of \code{x}.
|
|
|
|
void _nmod_poly_integral(mp_ptr x_int, mp_srcptr x, slong len, nmod_t mod)
|
|
|
|
Set the first \code{len} coefficients of \code{x_int} to the
|
|
integral of \code{x} which is assumed to be of length \code{len - 1}.
|
|
The constant term of \code{x_int} is set to zero.
|
|
It is assumed that \code{len > 0}. The result is only well-defined
|
|
if the modulus is a prime number strictly larger than the degree of
|
|
\code{x}.
|
|
|
|
void nmod_poly_integral(nmod_poly_t x_int, const nmod_poly_t x)
|
|
|
|
Set \code{x_int} to the indefinite integral of \code{x} with constant
|
|
term zero. The result is only well-defined if the modulus
|
|
is a prime number strictly larger than the degree of \code{x}.
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
Evaluation
|
|
|
|
*******************************************************************************
|
|
|
|
mp_limb_t _nmod_poly_evaluate_nmod(mp_srcptr poly, slong len, mp_limb_t c,
|
|
nmod_t mod)
|
|
|
|
Evaluates \code{poly} at the value~\code{c} and reduces modulo the
|
|
given modulus of \code{poly}. The value~\code{c} should be reduced
|
|
modulo the modulus. The algorithm used is Horner's method.
|
|
|
|
mp_limb_t nmod_poly_evaluate_nmod(nmod_poly_t poly, mp_limb_t c)
|
|
|
|
Evaluates \code{poly} at the value~\code{c} and reduces modulo the
|
|
modulus of \code{poly}. The value~\code{c} should be reduced modulo
|
|
the modulus. The algorithm used is Horner's method.
|
|
|
|
*******************************************************************************
|
|
|
|
Multipoint evaluation
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_evaluate_nmod_vec_iter(mp_ptr ys, mp_srcptr poly, slong len,
|
|
mp_srcptr xs, slong n, nmod_t mod)
|
|
|
|
Evaluates (\code{coeffs}, \code{len}) at the \code{n} values
|
|
given in the vector \code{xs}, writing the output values
|
|
to \code{ys}. The values in \code{xs} should be reduced
|
|
modulo the modulus.
|
|
|
|
Uses Horner's method iteratively.
|
|
|
|
void nmod_poly_evaluate_nmod_vec_iter(mp_ptr ys, const nmod_poly_t poly,
|
|
mp_srcptr xs, slong n)
|
|
|
|
Evaluates \code{poly} at the \code{n} values given in the vector
|
|
\code{xs}, writing the output values to \code{ys}. The values in
|
|
\code{xs} should be reduced modulo the modulus.
|
|
|
|
Uses Horner's method iteratively.
|
|
|
|
void _nmod_poly_evaluate_nmod_vec_fast_precomp(mp_ptr vs, mp_srcptr poly,
|
|
slong plen, const mp_ptr * tree, slong len, nmod_t mod)
|
|
|
|
Evaluates (\code{poly}, \code{plen}) at the \code{len} values given
|
|
by the precomputed subproduct tree \code{tree}.
|
|
|
|
void _nmod_poly_evaluate_nmod_vec_fast(mp_ptr ys, mp_srcptr poly,
|
|
slong len, mp_srcptr xs, slong n, nmod_t mod)
|
|
|
|
Evaluates (\code{coeffs}, \code{len}) at the \code{n} values
|
|
given in the vector \code{xs}, writing the output values
|
|
to \code{ys}. The values in \code{xs} should be reduced
|
|
modulo the modulus.
|
|
|
|
Uses fast multipoint evaluation, building a temporary subproduct tree.
|
|
|
|
void nmod_poly_evaluate_nmod_vec_fast(mp_ptr ys, const nmod_poly_t poly,
|
|
mp_srcptr xs, slong n)
|
|
|
|
Evaluates \code{poly} at the \code{n} values given in the vector
|
|
\code{xs}, writing the output values to \code{ys}. The values in
|
|
\code{xs} should be reduced modulo the modulus.
|
|
|
|
Uses fast multipoint evaluation, building a temporary subproduct tree.
|
|
|
|
|
|
void _nmod_poly_evaluate_nmod_vec(mp_ptr ys, mp_srcptr poly, slong len,
|
|
mp_srcptr xs, slong n, nmod_t mod)
|
|
|
|
Evaluates (\code{poly}, \code{len}) at the \code{n} values
|
|
given in the vector \code{xs}, writing the output values
|
|
to \code{ys}. The values in \code{xs} should be reduced
|
|
modulo the modulus.
|
|
|
|
void nmod_poly_evaluate_nmod_vec(mp_ptr ys, const nmod_poly_t poly,
|
|
mp_srcptr xs, slong n)
|
|
|
|
Evaluates \code{poly} at the \code{n} values given in the vector
|
|
\code{xs}, writing the output values to \code{ys}. The values in
|
|
\code{xs} should be reduced modulo the modulus.
|
|
|
|
*******************************************************************************
|
|
|
|
Interpolation
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_interpolate_nmod_vec(mp_ptr poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n, nmod_t mod)
|
|
|
|
Sets \code{poly} to the unique polynomial of length at most \code{n}
|
|
that interpolates the \code{n} given evaluation points \code{xs} and
|
|
values \code{ys}. If the interpolating polynomial is shorter than
|
|
length \code{n}, the leading coefficients are set to zero.
|
|
|
|
The values in \code{xs} and \code{ys} should be reduced modulo the
|
|
modulus, and all \code{xs} must be distinct. Aliasing between
|
|
\code{poly} and \code{xs} or \code{ys} is not allowed.
|
|
|
|
void nmod_poly_interpolate_nmod_vec(nmod_poly_t poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n)
|
|
|
|
Sets \code{poly} to the unique polynomial of length \code{n} that
|
|
interpolates the \code{n} given evaluation points \code{xs} and
|
|
values \code{ys}. The values in \code{xs} and \code{ys} should be
|
|
reduced modulo the modulus, and all \code{xs} must be distinct.
|
|
|
|
void _nmod_poly_interpolation_weights(mp_ptr w, const mp_ptr * tree,
|
|
slong len, nmod_t mod)
|
|
|
|
Sets \code{w} to the barycentric interpolation weights for fast
|
|
Lagrange interpolation with respect to a given subproduct tree.
|
|
|
|
void _nmod_poly_interpolate_nmod_vec_fast_precomp(mp_ptr poly, mp_srcptr ys,
|
|
const mp_ptr * tree, mp_srcptr weights, slong len, nmod_t mod)
|
|
|
|
Performs interpolation using the fast Lagrange interpolation
|
|
algorithm, generating a temporary subproduct tree.
|
|
|
|
The function values are given as \code{ys}. The function takes
|
|
a precomputed subproduct tree \code{tree} and barycentric
|
|
interpolation weights \code{weights} corresponding to the
|
|
roots.
|
|
|
|
void _nmod_poly_interpolate_nmod_vec_fast(mp_ptr poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n, nmod_t mod)
|
|
|
|
Performs interpolation using the fast Lagrange interpolation
|
|
algorithm, generating a temporary subproduct tree.
|
|
|
|
void nmod_poly_interpolate_nmod_vec_fast(nmod_poly_t poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n)
|
|
|
|
Performs interpolation using the fast Lagrange interpolation algorithm,
|
|
generating a temporary subproduct tree.
|
|
|
|
void _nmod_poly_interpolate_nmod_vec_newton(mp_ptr poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n, nmod_t mod)
|
|
|
|
Forms the interpolating polynomial in the Newton basis using
|
|
the method of divided differences and then converts it to
|
|
monomial form.
|
|
|
|
void nmod_poly_interpolate_nmod_vec_newton(nmod_poly_t poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n)
|
|
|
|
Forms the interpolating polynomial in the Newton basis using
|
|
the method of divided differences and then converts it to
|
|
monomial form.
|
|
|
|
void _nmod_poly_interpolate_nmod_vec_barycentric(mp_ptr poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n, nmod_t mod)
|
|
|
|
Forms the interpolating polynomial using a naive implementation
|
|
of the barycentric form of Lagrange interpolation.
|
|
|
|
void nmod_poly_interpolate_nmod_vec_barycentric(nmod_poly_t poly,
|
|
mp_srcptr xs, mp_srcptr ys, slong n)
|
|
|
|
Forms the interpolating polynomial using a naive implementation
|
|
of the barycentric form of Lagrange interpolation.
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
Composition
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_compose_horner(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Composes \code{poly1} of length \code{len1} with \code{poly2} of length
|
|
\code{len2} and sets \code{res} to the result, i.e.\ evaluates
|
|
\code{poly1} at \code{poly2}. The algorithm used is Horner's algorithm.
|
|
We require that \code{res} have space for \code{(len1 - 1)*(len2 - 1) + 1}
|
|
coefficients. It is assumed that \code{len1 > 0} and \code{len2 > 0}.
|
|
|
|
void nmod_poly_compose_horner(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2)
|
|
|
|
Composes \code{poly1} with \code{poly2} and sets \code{res} to the result,
|
|
i.e.\ evaluates \code{poly1} at \code{poly2}. The algorithm used is
|
|
Horner's algorithm.
|
|
|
|
void _nmod_poly_compose_divconquer(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Composes \code{poly1} of length \code{len1} with \code{poly2} of length
|
|
\code{len2} and sets \code{res} to the result, i.e.\ evaluates
|
|
\code{poly1} at \code{poly2}. The algorithm used is the divide and
|
|
conquer algorithm. We require that \code{res} have space for
|
|
\code{(len1 - 1)*(len2 - 1) + 1} coefficients. It is assumed that
|
|
\code{len1 > 0} and \code{len2 > 0}.
|
|
|
|
void nmod_poly_compose_divconquer(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2)
|
|
|
|
Composes \code{poly1} with \code{poly2} and sets \code{res} to the result,
|
|
i.e.\ evaluates \code{poly1} at \code{poly2}. The algorithm used is
|
|
the divide and conquer algorithm.
|
|
|
|
void _nmod_poly_compose(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Composes \code{poly1} of length \code{len1} with \code{poly2} of length
|
|
\code{len2} and sets \code{res} to the result, i.e.\ evaluates \code{poly1}
|
|
at \code{poly2}. We require that \code{res} have space for
|
|
\code{(len1 - 1)*(len2 - 1) + 1} coefficients. It is assumed that
|
|
\code{len1 > 0} and \code{len2 > 0}.
|
|
|
|
void nmod_poly_compose(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2)
|
|
|
|
Composes \code{poly1} with \code{poly2} and sets \code{res} to the result,
|
|
that is, evaluates \code{poly1} at \code{poly2}.
|
|
|
|
*******************************************************************************
|
|
|
|
Taylor shift
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_taylor_shift_horner(mp_ptr poly, mp_limb_t c,
|
|
slong len, nmod_t mod)
|
|
|
|
Performs the Taylor shift composing \code{poly} by $x+c$ in-place.
|
|
Uses an efficient version Horner's rule.
|
|
|
|
void nmod_poly_taylor_shift_horner(nmod_poly_t g,
|
|
const nmod_poly_t f, mp_limb_t c)
|
|
|
|
Performs the Taylor shift composing \code{f} by $x+c$.
|
|
|
|
void _nmod_poly_taylor_shift_convolution(mp_ptr poly, mp_limb_t c,
|
|
slong len, nmod_t mod)
|
|
|
|
Performs the Taylor shift composing \code{poly} by $x+c$ in-place.
|
|
Writes the composition as a single convolution with cost $O(M(n))$.
|
|
We require that the modulus is a prime at least as large as the length.
|
|
|
|
void nmod_poly_taylor_shift_convolution(nmod_poly_t g,
|
|
const nmod_poly_t f, mp_limb_t c)
|
|
|
|
Performs the Taylor shift composing \code{f} by $x+c$.
|
|
Writes the composition as a single convolution with cost $O(M(n))$.
|
|
We require that the modulus is a prime at least as large as the length.
|
|
|
|
void _nmod_poly_taylor_shift(mp_ptr poly, mp_limb_t c, slong len, nmod_t mod)
|
|
|
|
Performs the Taylor shift composing \code{poly} by $x+c$ in-place.
|
|
We require that the modulus is a prime.
|
|
|
|
void nmod_poly_taylor_shift(nmod_poly_t g, const nmod_poly_t f, mp_limb_t c)
|
|
|
|
Performs the Taylor shift composing \code{f} by $x+c$.
|
|
We require that the modulus is a prime.
|
|
|
|
*******************************************************************************
|
|
|
|
Modular composition
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_compose_mod_horner(mp_ptr res,
|
|
mp_srcptr f, slong lenf, mp_srcptr g, mp_srcptr h, slong lenh, nmod_t mod)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero and that the length of $g$ is one less than the
|
|
length of $h$ (possibly with zero padding). The output is not allowed
|
|
to be aliased with any of the inputs.
|
|
|
|
The algorithm used is Horner's rule.
|
|
|
|
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)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero. The algorithm used is Horner's rule.
|
|
|
|
|
|
void _nmod_poly_compose_mod_brent_kung(mp_ptr res,
|
|
mp_srcptr f, slong lenf, mp_srcptr g, mp_srcptr h, slong lenh, nmod_t mod)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero and that the length of $g$ is one less than the
|
|
length of $h$ (possibly with zero padding). We also require that
|
|
the length of $f$ is less than the length of $h$. The output is not allowed
|
|
to be aliased with any of the inputs.
|
|
|
|
The algorithm used is the Brent-Kung matrix algorithm.
|
|
|
|
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)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero and that $f$ has smaller degree than $h$.
|
|
The algorithm used is the Brent-Kung matrix algorithm.
|
|
|
|
void _nmod_poly_compose_mod_brent_kung_preinv(mp_ptr res, mp_srcptr f,
|
|
slong lenf,
|
|
mp_srcptr g, mp_srcptr h, slong lenh,
|
|
mp_srcptr hinv, slong lenhinv, nmod_t mod)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero and that the length of $g$ is one less than the
|
|
length of $h$ (possibly with zero padding). We also require that
|
|
the length of $f$ is less than the length of $h$. Furthermore, we require
|
|
\code{hinv} to be the inverse of the reverse of \code{h}.
|
|
The output is not allowed to be aliased with any of the inputs.
|
|
|
|
The algorithm used is the Brent-Kung matrix algorithm.
|
|
|
|
void nmod_poly_compose_mod_brent_kung_preinv(nmod_poly_t res,
|
|
const nmod_poly_t f, const nmod_poly_t g,
|
|
const nmod_poly_t h, const nmod_poly_t hinv)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero and that $f$ has smaller degree than $h$. Furthermore,
|
|
we require \code{hinv} to be the inverse of the reverse of \code{h}.
|
|
The algorithm used is the Brent-Kung matrix algorithm.
|
|
|
|
void
|
|
_nmod_poly_reduce_matrix_mod_poly (nmod_mat_t A, const nmod_mat_t B,
|
|
const nmod_poly_t f)
|
|
|
|
Sets the ith row of \code{A} to the reduction of the ith row of $B$ modulo
|
|
$f$ for $i=1,\ldots,\sqrt{\deg(f)}$. We require $B$ to be at least
|
|
a $\sqrt{\deg(f)}\times \deg(f)$ matrix and $f$ to be nonzero.
|
|
|
|
void
|
|
_nmod_poly_precompute_matrix (nmod_mat_t A, mp_srcptr f, mp_srcptr g,
|
|
slong leng, mp_srcptr ginv, slong lenginv, nmod_t mod)
|
|
|
|
Sets the ith row of \code{A} to $f^i$ modulo $g$ for
|
|
$i=1,\ldots,\sqrt{\deg(g)}$. We require $A$ to be
|
|
a $\sqrt{\deg(g)}\times \deg(g)$ matrix. We require
|
|
\code{ginv} to be the inverse of the reverse of \code{g} and $g$ to be
|
|
nonzero.
|
|
|
|
void
|
|
nmod_poly_precompute_matrix (nmod_mat_t A, const nmod_poly_t f,
|
|
const nmod_poly_t g, const nmod_poly_t ginv)
|
|
|
|
Sets the ith row of \code{A} to $f^i$ modulo $g$ for
|
|
$i=1,\ldots,\sqrt{\deg(g)}$. We require $A$ to be
|
|
a $\sqrt{\deg(g)}\times \deg(g)$ matrix. We require
|
|
\code{ginv} to be the inverse of the reverse of \code{g}.
|
|
|
|
|
|
void
|
|
_nmod_poly_compose_mod_brent_kung_precomp_preinv(mp_ptr res, mp_srcptr f,
|
|
slong lenf, const nmod_mat_t A, mp_srcptr h,
|
|
slong h, mp_srcptr hinv, slong lenhinv,
|
|
nmod_t mod)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero. We require that the ith row of $A$ contains $g^i$ for
|
|
$i=1,\ldots,\sqrt{\deg(h)}$, i.e. $A$ is a
|
|
$\sqrt{\deg(h)}\times \deg(h)$ matrix. We also require that
|
|
the length of $f$ is less than the length of $h$. Furthermore, we require
|
|
\code{hinv} to be the inverse of the reverse of \code{h}.
|
|
The output is not allowed to be aliased with any of the inputs.
|
|
|
|
The algorithm used is the Brent-Kung matrix algorithm.
|
|
|
|
void
|
|
nmod_poly_compose_mod_brent_kung_precomp_preinv(nmod_poly_t res,
|
|
const nmod_poly_t f, const nmod_mat_t A,
|
|
const nmod_poly_t h, const nmod_poly_t hinv)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that the
|
|
ith row of $A$ contains $g^i$ for $i=1,\ldots,\sqrt{\deg(h)}$, i.e. $A$ is a
|
|
$\sqrt{\deg(h)}\times \deg(h)$ matrix. We require that $h$ is nonzero and
|
|
that $f$ has smaller degree than $h$. Furthermore, we require \code{hinv} to
|
|
be the inverse of the reverse of \code{h}. This version of Brent-Kung
|
|
modular composition is particularly useful if one has to perform several
|
|
modular composition of the form $f(g)$ modulo $h$ for fixed $g$ and $h$.
|
|
|
|
void _nmod_poly_compose_mod(mp_ptr res,
|
|
mp_srcptr f, slong lenf, mp_srcptr g, mp_srcptr h, slong lenh, nmod_t mod)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero and that the length of $g$ is one less than the
|
|
length of $h$ (possibly with zero padding). The output is not allowed
|
|
to be aliased with any of the inputs.
|
|
|
|
void nmod_poly_compose_mod(nmod_poly_t res,
|
|
const nmod_poly_t f, const nmod_poly_t g,
|
|
const nmod_poly_t h)
|
|
|
|
Sets \code{res} to the composition $f(g)$ modulo $h$. We require that
|
|
$h$ is nonzero.
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
Greatest common divisor
|
|
|
|
*******************************************************************************
|
|
|
|
slong _nmod_poly_gcd_euclidean(mp_ptr G,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes the GCD of $A$ of length \code{lenA} and $B$ of length
|
|
\code{lenB}, where \code{lenA >= lenB > 0}. The length of the GCD $G$
|
|
is returned by the function. No attempt is made to make the GCD monic. It
|
|
is required that $G$ have space for \code{lenB} coefficients.
|
|
|
|
void nmod_poly_gcd_euclidean(nmod_poly_t G,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes the GCD of $A$ and $B$. The GCD of zero polynomials is
|
|
defined to be zero, whereas the GCD of the zero polynomial and some other
|
|
polynomial $P$ is defined to be $P$. Except in the case where
|
|
the GCD is zero, the GCD $G$ is made monic.
|
|
|
|
slong _nmod_poly_hgcd(mp_ptr *M, slong *lenM,
|
|
mp_ptr A, slong *lenA, mp_ptr B, slong *lenB,
|
|
mp_srcptr a, slong lena, mp_srcptr b, slong lenb,
|
|
nmod_t mod)
|
|
|
|
Computes the HGCD of $a$ and $b$, that is, a matrix~$M$, a sign~$\sigma$
|
|
and two polynomials $A$ and $B$ such that
|
|
\begin{equation*}
|
|
(A,B)^t = \sigma M^{-1} (a,b)^t.
|
|
\end{equation*}
|
|
|
|
Assumes that $\len(a) > \len(b) > 0$.
|
|
|
|
Assumes that $A$ and $B$ have space of size at least $\len(a)$
|
|
and $\len(b)$, respectively. On exit, \code{*lenA} and \code{*lenB}
|
|
will contain the correct lengths of $A$ and $B$.
|
|
|
|
Assumes that \code{M[0]}, \code{M[1]}, \code{M[2]}, and \code{M[3]}
|
|
each point to a vector of size at least $\len(a)$.
|
|
|
|
slong _nmod_poly_gcd_hgcd(mp_ptr G, mp_srcptr A, slong lenA,
|
|
mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes the monic GCD of $A$ and $B$, assuming that
|
|
$\len(A) \geq \len(B) > 0$.
|
|
|
|
Assumes that $G$ has space for $\len(B)$ coefficients and
|
|
returns the length of $G$ on output.
|
|
|
|
void nmod_poly_gcd_hgcd(nmod_poly_t G,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes the monic GCD of $A$ and $B$ using the HGCD algorithm.
|
|
|
|
As a special case, the GCD of two zero polynomials is defined to be
|
|
the zero polynomial.
|
|
|
|
The time complexity of the algorithm is $\mathcal{O}(n \log^2 n)$.
|
|
For further details, see~\citep{ThullYap1990}.
|
|
|
|
slong _nmod_poly_gcd(mp_ptr G,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, nmod_t mod)
|
|
|
|
Computes the GCD of $A$ of length \code{lenA} and $B$ of length
|
|
\code{lenB}, where \code{lenA >= lenB > 0}. The length of the GCD $G$
|
|
is returned by the function. No attempt is made to make the GCD monic. It
|
|
is required that $G$ have space for \code{lenB} coefficients.
|
|
|
|
void nmod_poly_gcd(nmod_poly_t G,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes the GCD of $A$ and $B$. The GCD of zero polynomials is
|
|
defined to be zero, whereas the GCD of the zero polynomial and some other
|
|
polynomial $P$ is defined to be $P$. Except in the case where
|
|
the GCD is zero, the GCD $G$ is made monic.
|
|
|
|
slong _nmod_poly_xgcd_euclidean(mp_ptr G, mp_ptr S, mp_ptr T,
|
|
mp_srcptr A, slong A_len, mp_srcptr B, slong B_len, nmod_t mod)
|
|
|
|
Computes the GCD of $A$ and $B$ together with cofactors $S$ and $T$
|
|
such that $S A + T B = G$. Returns the length of $G$.
|
|
|
|
Assumes that $\len(A) \geq \len(B) \geq 1$ and
|
|
$(\len(A),\len(B)) \neq (1,1)$.
|
|
|
|
No attempt is made to make the GCD monic.
|
|
|
|
Requires that $G$ have space for $\len(B)$ coefficients. Writes
|
|
$\len(B)-1$ and $\len(A)-1$ coefficients to $S$ and $T$, respectively.
|
|
Note that, in fact, $\len(S) \leq \max(\len(B) - \len(G), 1)$ and
|
|
$\len(T) \leq \max(\len(A) - \len(G), 1)$.
|
|
|
|
No aliasing of input and output operands is permitted.
|
|
|
|
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)
|
|
|
|
Computes the GCD of $A$ and $B$. The GCD of zero polynomials is
|
|
defined to be zero, whereas the GCD of the zero polynomial and some other
|
|
polynomial $P$ is defined to be $P$. Except in the case where
|
|
the GCD is zero, the GCD $G$ is made monic.
|
|
|
|
Polynomials \code{S} and \code{T} are computed such that
|
|
\code{S*A + T*B = G}. The length of \code{S} will be at most
|
|
\code{lenB} and the length of \code{T} will be at most \code{lenA}.
|
|
|
|
slong _nmod_poly_xgcd_hgcd(mp_ptr G, mp_ptr S, mp_ptr T,
|
|
mp_srcptr A, slong A_len, mp_srcptr B, slong B_len, nmod_t mod)
|
|
|
|
Computes the GCD of $A$ and $B$, where $\len(A) \geq \len(B) > 0$,
|
|
together with cofactors $S$ and $T$ such that $S A + T B = G$. Returns
|
|
the length of $G$.
|
|
|
|
No attempt is made to make the GCD monic.
|
|
|
|
Requires that $G$ have space for $\len(B)$ coefficients. Writes
|
|
$\len(B) - 1$ and $\len(A) - 1$ coefficients to $S$ and $T$,
|
|
respectively. Note that, in fact, $\len(S) \leq \len(B) - \len(G)$
|
|
and $\len(T) \leq \len(A) - \len(G)$.
|
|
|
|
Both $S$ and $T$ must have space for at least $2$ coefficients.
|
|
|
|
No aliasing of input and output operands is permitted.
|
|
|
|
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)
|
|
|
|
Computes the GCD of $A$ and $B$. The GCD of zero polynomials is
|
|
defined to be zero, whereas the GCD of the zero polynomial and some other
|
|
polynomial $P$ is defined to be $P$. Except in the case where
|
|
the GCD is zero, the GCD $G$ is made monic.
|
|
|
|
Polynomials \code{S} and \code{T} are computed such that
|
|
\code{S*A + T*B = G}. The length of \code{S} will be at most
|
|
\code{lenB} and the length of \code{T} will be at most \code{lenA}.
|
|
|
|
slong _nmod_poly_xgcd(mp_ptr G, mp_ptr S, mp_ptr T,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB,
|
|
nmod_t mod)
|
|
|
|
Computes the GCD of $A$ and $B$, where $\len(A) \geq \len(B) > 0$,
|
|
together with cofactors $S$ and $T$ such that $S A + T B = G$. Returns
|
|
the length of $G$.
|
|
|
|
No attempt is made to make the GCD monic.
|
|
|
|
Requires that $G$ have space for $\len(B)$ coefficients. Writes
|
|
$\len(B) - 1$ and $\len(A) - 1$ coefficients to $S$ and $T$,
|
|
respectively. Note that, in fact, $\len(S) \leq \len(B) - \len(G)$
|
|
and $\len(T) \leq \len(A) - \len(G)$.
|
|
|
|
No aliasing of input and output operands is permitted.
|
|
|
|
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)
|
|
|
|
Computes the GCD of $A$ and $B$. The GCD of zero polynomials is
|
|
defined to be zero, whereas the GCD of the zero polynomial and some other
|
|
polynomial $P$ is defined to be $P$. Except in the case where
|
|
the GCD is zero, the GCD $G$ is made monic.
|
|
|
|
The polynomials \code{S} and \code{T} are set such that
|
|
\code{S*A + T*B = G}. The length of \code{S} will be at most
|
|
\code{lenB} and the length of \code{T} will be at most \code{lenA}.
|
|
|
|
mp_limb_t
|
|
_nmod_poly_resultant_euclidean(mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Returns the resultant of \code{(poly1, len1)} and
|
|
\code{(poly2, len2)} using the Euclidean algorithm.
|
|
|
|
Assumes that \code{len1 >= len2 > 0}.
|
|
|
|
Asumes that the modulus is prime.
|
|
|
|
mp_limb_t
|
|
nmod_poly_resultant_euclidean(const nmod_poly_t f, const nmod_poly_t g)
|
|
|
|
Computes the resultant of $f$ and $g$ using the Euclidean algorithm.
|
|
|
|
For two non-zero polynomials $f(x) = a_m x^m + \dotsb + a_0$ and
|
|
$g(x) = b_n x^n + \dotsb + b_0$ of degrees $m$ and $n$, the resultant
|
|
is defined to be
|
|
\begin{equation*}
|
|
a_m^n b_n^m \prod_{(x, y) : f(x) = g(y) = 0} (x - y).
|
|
\end{equation*}
|
|
For convenience, we define the resultant to be equal to zero if either
|
|
of the two polynomials is zero.
|
|
|
|
mp_limb_t
|
|
_nmod_poly_resultant(mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, nmod_t mod)
|
|
|
|
Returns the resultant of \code{(poly1, len1)} and
|
|
\code{(poly2, len2)}.
|
|
|
|
Assumes that \code{len1 >= len2 > 0}.
|
|
|
|
Asumes that the modulus is prime.
|
|
|
|
mp_limb_t
|
|
nmod_poly_resultant(const nmod_poly_t f, const nmod_poly_t g)
|
|
|
|
Computes the resultant of $f$ and $g$.
|
|
|
|
For two non-zero polynomials $f(x) = a_m x^m + \dotsb + a_0$ and
|
|
$g(x) = b_n x^n + \dotsb + b_0$ of degrees $m$ and $n$, the resultant
|
|
is defined to be
|
|
\begin{equation*}
|
|
a_m^n b_n^m \prod_{(x, y) : f(x) = g(y) = 0} (x - y).
|
|
\end{equation*}
|
|
For convenience, we define the resultant to be equal to zero if either
|
|
of the two polynomials is zero.
|
|
|
|
slong _nmod_poly_gcdinv(mp_ptr G, mp_ptr S,
|
|
mp_srcptr A, slong lenA, mp_srcptr B, slong lenB,
|
|
const nmod_t mod)
|
|
|
|
Computes \code{(G, lenA)}, \code{(S, lenB-1)} such that
|
|
$G \cong S A \pmod{B}$, returning the actual length of $G$.
|
|
|
|
Assumes that $0 < \len(A) < \len(B)$.
|
|
|
|
void nmod_poly_gcdinv(nmod_poly_t G, nmod_poly_t S,
|
|
const nmod_poly_t A, const nmod_poly_t B)
|
|
|
|
Computes polynomials $G$ and $S$, both reduced modulo~$B$,
|
|
such that $G \cong S A \pmod{B}$, where $B$ is assumed to
|
|
have $\len(B) \geq 2$.
|
|
|
|
In the case that $A = 0 \pmod{B}$, returns $G = S = 0$.
|
|
|
|
int _nmod_poly_invmod(mp_ptr A, mp_srcptr B, slong lenB,
|
|
mp_srcptr P, slong lenP, const nmod_t mod)
|
|
|
|
Attempts to set \code{(A, lenP-1)} to the inverse of \code{(B, lenB)}
|
|
modulo the polynomial \code{(P, lenP)}. Returns $1$ if \code{(B, lenB)}
|
|
is invertible and $0$ otherwise.
|
|
|
|
Assumes that $0 < \len(B) < \len(P)$, and hence also $\len(P) \geq 2$,
|
|
but supports zero-padding in \code{(B, lenB)}.
|
|
|
|
Does not support aliasing.
|
|
|
|
Assumes that $mod$ is a prime number.
|
|
|
|
int nmod_poly_invmod(nmod_poly_t A, const nmod_poly_t B, const nmod_poly_t P)
|
|
|
|
Attempts to set $A$ to the inverse of $B$ modulo $P$ in the polynomial
|
|
ring $(\mathbf{Z}/p\mathbf{Z})[X]$, where we assume that $p$ is a prime
|
|
number.
|
|
|
|
If $\deg(P) < 2$, raises an exception.
|
|
|
|
If the greatest common divisor of $B$ and $P$ is~$1$, returns~$1$ and
|
|
sets $A$ to the inverse of $B$. Otherwise, returns~$0$ and the value
|
|
of $A$ on exit is undefined.
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
Power series composition
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_compose_series_horner(mp_ptr res,
|
|
mp_srcptr poly1, slong len1, mp_srcptr poly2, slong len2, slong n)
|
|
|
|
Sets \code{res} to the composition of \code{poly1} and \code{poly2}
|
|
modulo $x^n$, where the constant term of \code{poly2} is required
|
|
to be zero.
|
|
|
|
Assumes that \code{len1, len2, n > 0}, that \code{len1, len2 <= n},
|
|
and that \code{(len1-1) * (len2-1) + 1 <= n}, and that \code{res} has
|
|
space for \code{n} coefficients. Does not support aliasing between any
|
|
of the inputs and the output.
|
|
|
|
This implementation uses the Horner scheme.
|
|
|
|
void nmod_poly_compose_series_horner(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)
|
|
|
|
Sets \code{res} to the composition of \code{poly1} and \code{poly2}
|
|
modulo $x^n$, where the constant term of \code{poly2} is required
|
|
to be zero.
|
|
|
|
This implementation uses the Horner scheme.
|
|
|
|
void _nmod_poly_compose_series_brent_kung(mp_ptr res, mp_srcptr poly1,
|
|
slong len1, mp_srcptr poly2, slong len2, slong n)
|
|
|
|
Sets \code{res} to the composition of \code{poly1} and \code{poly2}
|
|
modulo $x^n$, where the constant term of \code{poly2} is required
|
|
to be zero.
|
|
|
|
Assumes that \code{len1, len2, n > 0}, that \code{len1, len2 <= n},
|
|
and that\\ \code{(len1-1) * (len2-1) + 1 <= n}, and that \code{res} has
|
|
space for \code{n} coefficients. Does not support aliasing between any
|
|
of the inputs and the output.
|
|
|
|
This implementation uses Brent-Kung algorithm 2.1 \cite{BrentKung1978}.
|
|
|
|
void nmod_poly_compose_series_brent_kung(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)
|
|
|
|
Sets \code{res} to the composition of \code{poly1} and \code{poly2}
|
|
modulo $x^n$, where the constant term of \code{poly2} is required
|
|
to be zero.
|
|
|
|
This implementation uses Brent-Kung algorithm 2.1 \cite{BrentKung1978}.
|
|
|
|
void _nmod_poly_compose_series_divconquer(mp_ptr res,
|
|
mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, slong N, nmod_t mod)
|
|
|
|
Composes \code{poly1} of length $\ell_1$ with \code{poly2} of
|
|
length $\ell_2$ modulo $x^N$ and sets \code{res} to the result,
|
|
i.e.\ evaluates \code{poly1} at \code{poly2}.
|
|
|
|
Writes $\min\{(\ell_1 - 1)(\ell_2 - 2) + 1, N\}$ coefficients
|
|
to the vector \code{res}.
|
|
|
|
The algorithm used is the divide and conquer algorithm.
|
|
It is assumed that $0 < \ell_1$ and $0 < \ell_2 \leq N$.
|
|
|
|
Does not support aliasing between the inputs and the output.
|
|
|
|
void nmod_poly_compose_series_divconquer(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, slong N)
|
|
|
|
Composes \code{poly1} with \code{poly2} modulo $x^N$ and sets \code{res}
|
|
to the result, i.e.\ evaluates \code{poly1} at \code{poly2}.
|
|
|
|
The algorithm used is the divide and conquer algorithm.
|
|
|
|
void _nmod_poly_compose_series(mp_ptr res, mp_srcptr poly1, slong len1,
|
|
mp_srcptr poly2, slong len2, slong n)
|
|
|
|
Sets \code{res} to the composition of \code{poly1} and \code{poly2}
|
|
modulo $x^n$, where the constant term of \code{poly2} is required
|
|
to be zero.
|
|
|
|
Assumes that \code{len1, len2, n > 0}, that \code{len1, len2 <= n},
|
|
and that\\ \code{(len1-1) * (len2-1) + 1 <= n}, and that \code{res} has
|
|
space for \code{n} coefficients. Does not support aliasing between any
|
|
of the inputs and the output.
|
|
|
|
This implementation automatically switches between the Horner scheme
|
|
and Brent-Kung algorithm 2.1 depending on the size of the inputs.
|
|
|
|
void nmod_poly_compose_series(nmod_poly_t res,
|
|
const nmod_poly_t poly1, const nmod_poly_t poly2, slong n)
|
|
|
|
Sets \code{res} to the composition of \code{poly1} and \code{poly2}
|
|
modulo $x^n$, where the constant term of \code{poly2} is required
|
|
to be zero.
|
|
|
|
This implementation automatically switches between the Horner scheme
|
|
and Brent-Kung algorithm 2.1 depending on the size of the inputs.
|
|
|
|
*******************************************************************************
|
|
|
|
Power series reversion
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_revert_series_lagrange(mp_ptr Qinv, mp_srcptr Q,
|
|
slong n, nmod_t mod)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$. The arguments must
|
|
both have length \code{n} and may not be aliased.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation uses the Lagrange inversion formula.
|
|
|
|
void nmod_poly_revert_series_lagrange(nmod_poly_t Qinv,
|
|
const nmod_poly_t Q, slong n)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation uses the Lagrange inversion formula.
|
|
|
|
void _nmod_poly_revert_series_lagrange_fast(mp_ptr Qinv, mp_srcptr Q,
|
|
slong n, nmod_t mod)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$. The arguments must
|
|
both have length \code{n} and may not be aliased.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation uses a reduced-complexity implementation
|
|
of the Lagrange inversion formula.
|
|
|
|
void nmod_poly_revert_series_lagrange_fast(nmod_poly_t Qinv,
|
|
const nmod_poly_t Q, slong n)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation uses a reduced-complexity implementation
|
|
of the Lagrange inversion formula.
|
|
|
|
void _nmod_poly_revert_series_newton(mp_ptr Qinv, mp_srcptr Q,
|
|
slong n, nmod_t mod)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$. The arguments must
|
|
both have length \code{n} and may not be aliased.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation uses Newton iteration \cite{BrentKung1978}.
|
|
|
|
void nmod_poly_revert_series_newton(nmod_poly_t Qinv,
|
|
const nmod_poly_t Q, slong n)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation uses Newton iteration \cite{BrentKung1978}.
|
|
|
|
void _nmod_poly_revert_series(mp_ptr Qinv, mp_srcptr Q, slong n, nmod_t mod)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$. The arguments must
|
|
both have length \code{n} and may not be aliased.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation automatically chooses between the Lagrange
|
|
inversion formula and Newton iteration based on the size of the
|
|
input.
|
|
|
|
void nmod_poly_revert_series(nmod_poly_t Qinv, const nmod_poly_t Q, slong n)
|
|
|
|
Sets \code{Qinv} to the compositional inverse or reversion of \code{Q}
|
|
as a power series, i.e. computes $Q^{-1}$ such that
|
|
$Q(Q^{-1}(x)) = Q^{-1}(Q(x)) = x \bmod x^n$.
|
|
|
|
It is required that $Q_0 = 0$ and that $Q_1$ as well as the integers
|
|
$1, 2, \ldots, n-1$ are invertible modulo the modulus.
|
|
|
|
This implementation automatically chooses between the Lagrange
|
|
inversion formula and Newton iteration based on the size of the
|
|
input.
|
|
|
|
*******************************************************************************
|
|
|
|
Square roots
|
|
|
|
The series expansions for $\sqrt{h}$ and $1/\sqrt{h}$ are defined
|
|
by means of the generalised binomial theorem
|
|
$$h^r = (1+y)^r =
|
|
\sum_{k=0}^{\infty} {r \choose k} y^k.$$
|
|
It is assumed that $h$ has constant term $1$ and that the coefficients
|
|
$2^{-k}$ exist in the coefficient ring (i.e. $2$ must be invertible).
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_invsqrt_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set the first $n$ terms of $g$ to the series expansion of $1/\sqrt{h}$.
|
|
It is assumed that $n > 0$, that $h$ has constant term 1 and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing is not permitted.
|
|
|
|
void nmod_poly_invsqrt_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g$ to the series expansion of $1/\sqrt{h}$ to order $O(x^n)$.
|
|
It is assumed that $h$ has constant term 1.
|
|
|
|
void _nmod_poly_sqrt_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set the first $n$ terms of $g$ to the series expansion of $\sqrt{h}$.
|
|
It is assumed that $n > 0$, that $h$ has constant term 1 and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing is not permitted.
|
|
|
|
void nmod_poly_sqrt_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g$ to the series expansion of $\sqrt{h}$ to order $O(x^n)$.
|
|
It is assumed that $h$ has constant term 1.
|
|
|
|
int _nmod_poly_sqrt(mp_ptr s, mp_srcptr p, slong n, nmod_t mod)
|
|
|
|
If \code{(p, n)} is a perfect square, sets \code{(s, n / 2 + 1)}
|
|
to a square root of $p$ and returns 1. Otherwise returns 0.
|
|
|
|
int nmod_poly_sqrt(nmod_poly_t s, const nmod_poly_t p)
|
|
|
|
If $p$ is a perfect square, sets $s$ to a square root of $p$
|
|
and returns 1. Otherwise returns 0.
|
|
|
|
*******************************************************************************
|
|
|
|
Transcendental functions
|
|
|
|
The elementary transcendental functions of a formal power series $h$
|
|
are defined as
|
|
|
|
$$\exp(h(x)) = \sum_{k=0}^{\infty} \frac{(h(x))^k}{k!}$$
|
|
|
|
$$\log(h(x)) = \int_0^x \frac{h'(t)}{h(t)} dt$$
|
|
|
|
$$\operatorname{atan}(h(x)) = \int_0^x\frac{h'(t)}{1+(h(t))^2} dt$$
|
|
|
|
$$\operatorname{atanh}(h(x)) = \int_0^x\frac{h'(t)}{1-(h(t))^2} dt$$
|
|
|
|
$$\operatorname{asin}(h(x)) = \int_0^x\frac{h'(t)}{\sqrt{1-(h(t))^2}} dt$$
|
|
|
|
$$\operatorname{asinh}(h(x)) = \int_0^x\frac{h'(t)}{\sqrt{1+(h(t))^2}} dt$$
|
|
|
|
The functions sin, cos, tan, etc. are defined using standard inverse
|
|
or functional relations.
|
|
|
|
The logarithm function assumes that $h$ has constant term $1$. All
|
|
other functions assume that $h$ has constant term $0$.
|
|
|
|
All functions assume that the coefficient $1/k$ or $1/k!$ exists
|
|
for all indices $k$. When computing to order $O(x^n)$, the modulus $p$
|
|
must therefore be a prime satisfying $p \ge n$. Further, we always
|
|
require that $p > 2$ in order to be able to multiply by $1/2$ for
|
|
internal purposes.
|
|
|
|
If the input does not satisfy all these conditions, results are undefined.
|
|
|
|
Except where otherwise noted, functions are implemented with optimal
|
|
(up to constants) complexity $O(M(n))$, where $M(n)$ is the cost
|
|
of polynomial multiplication.
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_log_series_monomial_ui(mp_ptr g,
|
|
mp_limb_t c, ulong r, slong n, nmod_t mod)
|
|
|
|
Set $g = \log(1+cx^r) + O(x^n)$. Assumes $n > 0$, $r > 0$, and that
|
|
the coefficient is reduced by the modulus. Works efficiently in linear
|
|
time.
|
|
|
|
void nmod_poly_log_series_monomial_ui(nmod_poly_t g,
|
|
mp_limb_t c, ulong r, slong n)
|
|
|
|
Set $g = \log(1+cx^r) + O(x^n)$. Works efficiently in linear time.
|
|
|
|
void _nmod_poly_log_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \log(h) + O(x^n)$. Assumes $n > 0$ and that $h$ is zero-padded
|
|
as necessary to length $n$. Aliasing of $g$ and $h$ is allowed.
|
|
|
|
void nmod_poly_log_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \log(h) + O(x^n)$. The case $h = 1+cx^r$ is automatically
|
|
detected and handled efficiently.
|
|
|
|
void _nmod_poly_exp_series_monomial_ui(mp_ptr g,
|
|
mp_limb_t c, ulong r, slong n, nmod_t mod)
|
|
|
|
Set $g = \exp(cx^r) + O(x^n)$. Assumes $n > 0$, $r > 0$, and that
|
|
the coefficient is reduced by the modulus. Works efficiently
|
|
in linear time.
|
|
|
|
void nmod_poly_exp_series_monomial_ui(nmod_poly_t g,
|
|
mp_limb_t c, ulong r, slong n)
|
|
|
|
Set $g = \exp(cx^r) + O(x^n)$. Works efficiently in linear time.
|
|
|
|
void _nmod_poly_exp_series_basecase(mp_ptr g, mp_srcptr h, slong hlen,
|
|
slong n, nmod_t mod)
|
|
|
|
Set $g = \exp(h) + O(x^n)$ using a simple $O(n^2)$ algorithm.
|
|
Assumes $n > 0$ and $\operatorname{hlen} > 0$. Only the first
|
|
$\operatorname{hlen}$ coefficients of $h$ will be read.
|
|
Aliasing of $f$ and $h$ is allowed.
|
|
|
|
void nmod_poly_exp_series_basecase(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \exp(h) + O(x^n)$ using a simple $O(n^2)$ algorithm.
|
|
|
|
void _nmod_poly_exp_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \exp(h) + O(x^n)$. Assumes $n > 0$ and that $h$ is zero-padded
|
|
as necessary to length $n$. Aliasing of $g$ and $h$ is not allowed.
|
|
|
|
Uses Newton iteration (the version given in \cite{HanZim2004}).
|
|
For small $n$, falls back to the basecase algorithm.
|
|
|
|
void _nmod_poly_exp_expinv_series(mp_ptr f, mp_ptr g, mp_srcptr h,
|
|
slong n, nmod_t mod)
|
|
|
|
Set $f = \exp(h) + O(x^n)$ and $g = \exp(-h) + O(x^n)$, more efficiently
|
|
for large $n$ than performing a separate inversion to obtain $g$.
|
|
Assumes $n > 0$ and that $h$ is zero-padded
|
|
as necessary to length $n$. Aliasing is not allowed.
|
|
|
|
Uses Newton iteration (the version given in \cite{HanZim2004}).
|
|
For small $n$, falls back to the basecase algorithm.
|
|
|
|
void nmod_poly_exp_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \exp(h) + O(x^n)$. The case $h = cx^r$ is automatically
|
|
detected and handled efficiently. Otherwise this function automatically
|
|
uses the basecase algorithm for small $n$ and Newton iteration otherwise.
|
|
|
|
void _nmod_poly_atan_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{atan}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
allowed.
|
|
|
|
void nmod_poly_atan_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{atan}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_atanh_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{atanh}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
allowed.
|
|
|
|
void nmod_poly_atanh_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{atanh}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_asin_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{asin}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
allowed.
|
|
|
|
void nmod_poly_asin_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{asin}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_asinh_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{asinh}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
allowed.
|
|
|
|
void nmod_poly_asinh_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{asinh}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_sin_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{sin}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
allowed. The value is computed using the identity
|
|
$\sin(x) = 2 \tan(x/2)) / (1 + \tan^2(x/2)).$
|
|
|
|
void nmod_poly_sin_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{sin}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_cos_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{cos}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
allowed. The value is computed using the identity
|
|
$\cos(x) = (1-\tan^2(x/2)) / (1 + \tan^2(x/2)).$
|
|
|
|
void nmod_poly_cos_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{cos}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_tan_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{tan}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
not allowed. Uses Newton iteration to invert the atan function.
|
|
|
|
void nmod_poly_tan_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{tan}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_sinh_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{sinh}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
not allowed. Uses the identity $\sinh(x) = (e^x - e^{-x})/2$.
|
|
|
|
void nmod_poly_sinh_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{sinh}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_cosh_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{cos}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Aliasing of $g$ and $h$ is
|
|
not allowed. Uses the identity $\cosh(x) = (e^x + e^{-x})/2$.
|
|
|
|
void nmod_poly_cosh_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{cosh}(h) + O(x^n)$.
|
|
|
|
void _nmod_poly_tanh_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod)
|
|
|
|
Set $g = \operatorname{tanh}(h) + O(x^n)$. Assumes $n > 0$ and that $h$
|
|
is zero-padded as necessary to length $n$. Uses the identity
|
|
$\tanh(x) = (e^{2x}-1)/(e^{2x}+1)$.
|
|
|
|
void nmod_poly_tanh_series(nmod_poly_t g, const nmod_poly_t h, slong n)
|
|
|
|
Set $g = \operatorname{tanh}(h) + O(x^n)$.
|
|
|
|
*******************************************************************************
|
|
|
|
Products
|
|
|
|
*******************************************************************************
|
|
|
|
void _nmod_poly_product_roots_nmod_vec(mp_ptr poly, mp_srcptr xs,
|
|
slong n, nmod_t mod)
|
|
|
|
Sets \code{(poly, n + 1)} to the monic polynomial which is the product
|
|
of $(x - x_0)(x - x_1) \cdots (x - x_{n-1})$, the roots $x_i$ being
|
|
given by \code{xs}.
|
|
|
|
Aliasing of the input and output is not allowed.
|
|
|
|
void nmod_poly_product_roots_nmod_vec(nmod_poly_t poly, mp_srcptr xs, slong n)
|
|
|
|
Sets \code{poly} to the monic polynomial which is the product
|
|
of $(x - x_0)(x - x_1) \cdots (x - x_{n-1})$, the roots $x_i$ being
|
|
given by \code{xs}.
|
|
|
|
*******************************************************************************
|
|
|
|
Subproduct trees
|
|
|
|
*******************************************************************************
|
|
|
|
mp_ptr * _nmod_poly_tree_alloc(slong len)
|
|
|
|
Allocates space for a subproduct tree of the given length, having
|
|
linear factors at the lowest level.
|
|
|
|
Entry $i$ in the tree is a pointer to a single array of limbs,
|
|
capable of storing $\lfloor n / 2^i \rfloor$ subproducts of
|
|
degree $2^i$ adjacently, plus a trailing entry if $n / 2^i$ is
|
|
not an integer.
|
|
|
|
For example, a tree of length 7 built from monic linear factors has
|
|
the following structure, where spaces have been inserted
|
|
for illustrative purposes:
|
|
|
|
\begin{verbatim}
|
|
X1 X1 X1 X1 X1 X1 X1
|
|
XX1 XX1 XX1 X1
|
|
XXXX1 XX1 X1
|
|
XXXXXXX1
|
|
\end{verbatim}
|
|
|
|
void _nmod_poly_tree_free(mp_ptr * tree, slong len)
|
|
|
|
Free the allocated space for the subproduct.
|
|
|
|
void _nmod_poly_tree_build(mp_ptr * tree, mp_srcptr roots, slong len,
|
|
nmod_t mod)
|
|
|
|
Builds a subproduct tree in the preallocated space from
|
|
the \code{len} monic linear factors $(x-r_i)$. The top level
|
|
product is not computed.
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
Inflation and deflation
|
|
|
|
*******************************************************************************
|
|
|
|
void nmod_poly_inflate(nmod_poly_t result, const nmod_poly_t input,
|
|
ulong inflation)
|
|
|
|
Sets \code{result} to the inflated polynomial $p(x^n)$ where
|
|
$p$ is given by \code{input} and $n$ is given by \code{deflation}.
|
|
|
|
void nmod_poly_deflate(nmod_poly_t result, const nmod_poly_t input,
|
|
ulong deflation)
|
|
|
|
Sets \code{result} to the deflated polynomial $p(x^{1/n})$ where
|
|
$p$ is given by \code{input} and $n$ is given by \code{deflation}.
|
|
Requires $n > 0$.
|
|
|
|
ulong nmod_poly_deflation(const nmod_poly_t input)
|
|
|
|
Returns the largest integer by which \code{input} can be deflated.
|
|
As special cases, returns 0 if \code{input} is the zero polynomial
|
|
and 1 of \code{input} is a constant polynomial.
|