Polynomial arithmetic is implemented using the FFT, combined with the Chinese Remainder Theorem. A more detailed description of the techniques used here can be found in [Shoup, J. Symbolic Comp. 20:363-397, 1995].
Small degree polynomials are multiplied either with classical or Karatsuba algorithms.
charpoly_mod,
clear,
constant_term,
copy,
degree,
derivative,
discriminant,
factor,
gcd,
invert_and_truncate,
is_monic,
is_one,
is_x,
is_zero,
leading_coefficient,
left_shift,
linear_roots,
minpoly_mod,
multiply_and_truncate,
multiply_mod,
norm_mod,
preallocate_space,
quo_rem,
resultant,
reverse,
right_shift,
set_x,
square,
square_and_truncate,
trace_list,
trace_mod,
truncate,
xgcd
Further documentation:
) |
Return the characteristic polynomial of this polynomial modulo the modulus. The modulus must be monic of degree bigger than self.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([1,2,0,3]) sage: mod = ntl.ZZ_pX([-5,2,0,0,1]) sage: f.charpoly_mod(mod) [11 1 8 14 1]
) |
Reset this polynomial to 0. Changes this polynomial in place.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([1,2,3]) sage: f [1 2 3] sage: f.clear() sage: f []
) |
Return the constant coefficient of this polynomial.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([3,6,9]) sage: f.constant_term() 3 sage: f = ntl.ZZ_pX() sage: f.constant_term() 0
) |
Return the degree of this polynomial. The degree of the 0 polynomial is -1.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([5,0,1]) sage: f.degree() 2 sage: f = ntl.ZZ_pX(range(100)) sage: f.degree() 99 sage: f = ntl.ZZ_pX() sage: f.degree() -1 sage: f = ntl.ZZ_pX([1]) sage: f.degree() 0
) |
Return the derivative of this polynomial.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,7,0,13]) sage: f.derivative() [7 0 19]
) |
Return the discriminant of a=self, which is by definition
where m = deg(a), and lc(a) is the leading coefficient of a.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([1,2,0,3]) sage: f.discriminant() 1
) |
Return the gcd d = gcd(a, b), where by convention the leading coefficient of d is >= 0. We uses a multi-modular algorithm.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([1,2,3]) * ntl.ZZ_pX([4,5])**2 sage: g = ntl.ZZ_pX([1,1,1])**3 * ntl.ZZ_pX([1,2,3]) sage: f.gcd(g) [6 12 1] sage: g.gcd(f) [6 12 1]
) |
Compute and return the inverse of self modulo
.
The constant term of self must be 1 or -1.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,3,4,5,6,7]) sage: f.invert_and_truncate(20) [1 18 1 0 0 0 0 8 17 2 13 0 0 0 4 0 17 10 9] sage: g = f.invert_and_truncate(20) sage: g * f [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 4 4 3]
) |
Return True exactly if this polynomial is monic.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([2,0,0,1]) sage: f.is_monic() True sage: g = f.reverse() sage: g.is_monic() False sage: g [1 0 0 2]
) |
Return True exactly if this polynomial is 1.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,1]) sage: f.is_one() False sage: f = ntl.ZZ_pX([1]) sage: f.is_one() True
) |
True if this is the polynomial "x".
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX() sage: f.set_x() sage: f.is_x() True sage: f = ntl.ZZ_pX([0,1]) sage: f.is_x() True sage: f = ntl.ZZ_pX([1]) sage: f.is_x() False
) |
Return True exactly if this polynomial is 0.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([0,0,0,20]) sage: f.is_zero() True sage: f = ntl.ZZ_pX([0,0,1]) sage: f [0 0 1] sage: f.is_zero() False
) |
Return the leading coefficient of this polynomial.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([3,6,9]) sage: f.leading_coefficient() 9 sage: f = ntl.ZZ_pX() sage: f.leading_coefficient() 0
) |
Return the polynomial obtained by shifting all coefficients of this polynomial to the left n positions.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([2,0,0,1]) sage: f [2 0 0 1] sage: f.left_shift(2) [0 0 2 0 0 1] sage: f.left_shift(5) [0 0 0 0 0 2 0 0 1]
A negative left shift is a right shift.
sage: f.left_shift(-2) [0 1]
) |
Assumes that input is monic, and has deg(f) distinct roots. Returns the list of roots.
) |
Return the minimal polynomial of this polynomial modulo the modulus. The modulus must be monic of degree bigger than self.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([0,0,1]) sage: g = f*f sage: f.charpoly_mod(g) [0 0 0 0 1]
However, since
moduluo
, its minimal polynomial
is of degree
.
sage: f.minpoly_mod(g) [0 0 1]
) |
Return self*other but with terms of degree >= m removed.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,3,4,5]) sage: g = ntl.ZZ_pX([10]) sage: f.multiply_and_truncate(g, 2) [10] sage: g.multiply_and_truncate(f, 2) [10]
) |
Return self*other deg(modulus) > 0, and self and other must have smaller degree.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: modulus = ntl.ZZ_pX([1,2,0,1]) # must be monic sage: g = ntl.ZZ_pX([-1,0,1]) sage: h = ntl.ZZ_pX([3,7,13]) sage: h.multiply_mod(g, modulus) [10 6 4]
) |
Return the norm of this polynomial modulo the modulus. The modulus must be monic, and of positive degree strictly greater than the degree of self.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([1,2,0,3]) sage: mod = ntl.ZZ_pX([-5,2,0,0,1]) sage: f.norm_mod(mod) 11
The norm is the constant term of the characteristic polynomial.
sage: f.charpoly_mod(mod) [11 1 8 14 1]
) |
Pre-allocate spaces for n coefficients. The polynomial that f represents is unchanged. This is useful if you know you'll be setting coefficients up to n, so memory isn't re-allocated as the polynomial grows. (You might save a millisecond with this function.)
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([1,2,3]) sage: f.preallocate_space(20) sage: f [1 2 3] sage: f[10]=5 # no new memory is allocated sage: f [1 2 3 0 0 0 0 0 0 0 5]
) |
Returns the unique integral q and r such that self = q*other + r, if they exist. Otherwise raises an Exception.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX(range(10)); g = ntl.ZZ_pX([-1,0,1]) sage: q, r = f.quo_rem(g) sage: q, r ([3 7 1 4 14 16 8 9], [3 8]) sage: q*g + r == f True
) |
Return the resultant of self and other.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([17,0,1,1]) sage: g = ntl.ZZ_pX([34,-17,18,2]) sage: f.resultant(g) 0
) |
Return the polynomial obtained by reversing the coefficients of this polynomial. If hi is set then this function behaves as if this polynomial has degree hi.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,3,4,5]) sage: f.reverse() [5 4 3 2 1] sage: f.reverse(hi=10) [0 0 0 0 0 0 5 4 3 2 1] sage: f.reverse(hi=2) [3 2 1] sage: f.reverse(hi=-2) []
) |
Return the polynomial obtained by shifting all coefficients of this polynomial to the right n positions.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([2,0,0,1]) sage: f [2 0 0 1] sage: f.right_shift(2) [0 1] sage: f.right_shift(5) [] sage: f.right_shift(-2) [0 0 2 0 0 1]
) |
Set this polynomial to the monomial "x".
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX() sage: f.set_x() sage: f [0 1] sage: g = ntl.ZZ_pX([0,1]) sage: f == g True
Though f and g are equal, they are not the same objects in memory:
sage: f is g False
) |
Return f*f.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([-1,0,1]) sage: f*f [1 0 15 0 1]
) |
Return self*self but with terms of degree >= m removed.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,3,4,5]) sage: f.square_and_truncate(4) [1 4 10] sage: (f*f).truncate(4) [1 4 10]
) |
Return the list of traces of the powers
of the
monomial x modulo this polynomial for i = 0, ..., deg(f)-1.
This polynomial must be monic.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,0,3,0,1]) sage: f.trace_list() [5, 0, 14, 0, 10]
The input polynomial must be monic or a ValueError is raised:
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,0,3,0,2]) sage: f.trace_list() Traceback (most recent call last): ... ValueError: polynomial must be monic.
) |
Return the trace of this polynomial modulus the modulus. The modulus must be monic, and of positive degree degree bigger than the the degree of self.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,0,3]) sage: mod = ntl.ZZ_pX([5,3,-1,1,1]) sage: f.trace_mod(mod) 3
) |
Return the truncation of this polynomial obtained by removing all terms of degree >= m.
sage: ntl.set_modulus(ntl.ZZ(20)) sage: f = ntl.ZZ_pX([1,2,3,4,5]) sage: f.truncate(3) [1 2 3] sage: f.truncate(8) [1 2 3 4 5] sage: f.truncate(1) [1] sage: f.truncate(0) [] sage: f.truncate(-1) [] sage: f.truncate(-5) []
) |
Returns r,s,t such that r = s*self + t*other.
Here r is the resultant of a and b; if r != 0, then this function computes s and t such that: a*s + b*t = r; otherwise s and t are both 0.
sage: ntl.set_modulus(ntl.ZZ(17)) sage: f = ntl.ZZ_pX([1,2,3]) * ntl.ZZ_pX([4,5])**2 sage: g = ntl.ZZ_pX([1,1,1])**3 * ntl.ZZ_pX([1,2,3]) sage: f.xgcd(g) # nothing since they are not coprime ([6 12 1], [15 13 6 8 7 9], [4 13])
In this example the input quadratic polynomials have a common root modulo 13.
sage: f = ntl.ZZ_pX([5,0,1]) sage: g = ntl.ZZ_pX([18,0,1]) sage: f.xgcd(g) ([1], [13], [4])
Instances of class ZZ_pX_class also have the following special methods:
__add__,
__cmp__,
__delitem__,
__div__,
__getitem__,
__mod__,
__mul__,
__neg__,
__pow__,
__radd__,
__rdiv__,
__repr__,
__rmod__,
__rmul__,
__rpow__,
__rsub__,
__setitem__,
__sub__
See About this document... for information on suggesting changes.