passagemath-ntl 10.6.38__cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-ntl might be problematic. Click here for more details.
- passagemath_ntl/__init__.py +3 -0
- passagemath_ntl-10.6.38.dist-info/METADATA +122 -0
- passagemath_ntl-10.6.38.dist-info/RECORD +162 -0
- passagemath_ntl-10.6.38.dist-info/WHEEL +6 -0
- passagemath_ntl-10.6.38.dist-info/top_level.txt +3 -0
- passagemath_ntl.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
- passagemath_ntl.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_ntl.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
- passagemath_ntl.libs/libmpfr-9d41ebf1.so.6.2.1 +0 -0
- passagemath_ntl.libs/libntl-1bc30f7e.so.45.0.0 +0 -0
- sage/all__sagemath_ntl.py +7 -0
- sage/libs/all__sagemath_ntl.py +3 -0
- sage/libs/mpfi/__init__.pxd +287 -0
- sage/libs/mpfi/types.pxd +10 -0
- sage/libs/ntl/GF2.pxd +18 -0
- sage/libs/ntl/GF2E.pxd +28 -0
- sage/libs/ntl/GF2EX.pxd +12 -0
- sage/libs/ntl/GF2X.pxd +81 -0
- sage/libs/ntl/ZZ.pxd +93 -0
- sage/libs/ntl/ZZX.pxd +85 -0
- sage/libs/ntl/ZZ_p.pxd +28 -0
- sage/libs/ntl/ZZ_pE.pxd +37 -0
- sage/libs/ntl/ZZ_pEX.pxd +106 -0
- sage/libs/ntl/ZZ_pX.pxd +122 -0
- sage/libs/ntl/__init__.py +4 -0
- sage/libs/ntl/all.py +72 -0
- sage/libs/ntl/conversion.pxd +106 -0
- sage/libs/ntl/convert.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/convert.pxd +7 -0
- sage/libs/ntl/convert.pyx +38 -0
- sage/libs/ntl/decl.pxi +18 -0
- sage/libs/ntl/error.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/error.pyx +63 -0
- sage/libs/ntl/lzz_p.pxd +20 -0
- sage/libs/ntl/lzz_pX.pxd +59 -0
- sage/libs/ntl/mat_GF2.pxd +30 -0
- sage/libs/ntl/mat_GF2E.pxd +30 -0
- sage/libs/ntl/mat_ZZ.pxd +59 -0
- sage/libs/ntl/misc.pxi +33 -0
- sage/libs/ntl/ntl_GF2.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_GF2.pxd +5 -0
- sage/libs/ntl/ntl_GF2.pyx +281 -0
- sage/libs/ntl/ntl_GF2E.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_GF2E.pxd +8 -0
- sage/libs/ntl/ntl_GF2E.pyx +488 -0
- sage/libs/ntl/ntl_GF2EContext.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_GF2EContext.pxd +9 -0
- sage/libs/ntl/ntl_GF2EContext.pyx +134 -0
- sage/libs/ntl/ntl_GF2EX.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_GF2EX.pxd +10 -0
- sage/libs/ntl/ntl_GF2EX.pyx +251 -0
- sage/libs/ntl/ntl_GF2X.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_GF2X.pxd +5 -0
- sage/libs/ntl/ntl_GF2X.pyx +771 -0
- sage/libs/ntl/ntl_GF2X_linkage.pxi +404 -0
- sage/libs/ntl/ntl_ZZ.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZ.pxd +7 -0
- sage/libs/ntl/ntl_ZZ.pyx +541 -0
- sage/libs/ntl/ntl_ZZX.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZX.pxd +7 -0
- sage/libs/ntl/ntl_ZZX.pyx +1206 -0
- sage/libs/ntl/ntl_ZZ_p.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZ_p.pxd +10 -0
- sage/libs/ntl/ntl_ZZ_p.pyx +509 -0
- sage/libs/ntl/ntl_ZZ_pContext.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZ_pContext.pxd +22 -0
- sage/libs/ntl/ntl_ZZ_pContext.pyx +201 -0
- sage/libs/ntl/ntl_ZZ_pE.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZ_pE.pxd +11 -0
- sage/libs/ntl/ntl_ZZ_pE.pyx +349 -0
- sage/libs/ntl/ntl_ZZ_pEContext.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZ_pEContext.pxd +23 -0
- sage/libs/ntl/ntl_ZZ_pEContext.pyx +226 -0
- sage/libs/ntl/ntl_ZZ_pEX.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZ_pEX.pxd +10 -0
- sage/libs/ntl/ntl_ZZ_pEX.pyx +1255 -0
- sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi +420 -0
- sage/libs/ntl/ntl_ZZ_pX.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_ZZ_pX.pxd +17 -0
- sage/libs/ntl/ntl_ZZ_pX.pyx +1532 -0
- sage/libs/ntl/ntl_lzz_p.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_lzz_p.pxd +8 -0
- sage/libs/ntl/ntl_lzz_p.pyx +440 -0
- sage/libs/ntl/ntl_lzz_pContext.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_lzz_pContext.pxd +7 -0
- sage/libs/ntl/ntl_lzz_pContext.pyx +137 -0
- sage/libs/ntl/ntl_lzz_pX.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_lzz_pX.pxd +10 -0
- sage/libs/ntl/ntl_lzz_pX.pyx +902 -0
- sage/libs/ntl/ntl_mat_GF2.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_mat_GF2.pxd +8 -0
- sage/libs/ntl/ntl_mat_GF2.pyx +612 -0
- sage/libs/ntl/ntl_mat_GF2E.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_mat_GF2E.pxd +10 -0
- sage/libs/ntl/ntl_mat_GF2E.pyx +752 -0
- sage/libs/ntl/ntl_mat_ZZ.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/ntl/ntl_mat_ZZ.pxd +6 -0
- sage/libs/ntl/ntl_mat_ZZ.pyx +1523 -0
- sage/libs/ntl/ntl_tools.pxd +3 -0
- sage/libs/ntl/ntlwrap.h +53 -0
- sage/libs/ntl/ntlwrap_impl.h +743 -0
- sage/libs/ntl/types.pxd +157 -0
- sage/libs/ntl/vec_GF2.pxd +26 -0
- sage/libs/ntl/vec_GF2E.pxd +2 -0
- sage/matrix/all__sagemath_ntl.py +1 -0
- sage/matrix/matrix_modn_dense_double.pxd +10 -0
- sage/matrix/matrix_modn_dense_float.pxd +9 -0
- sage/matrix/matrix_modn_dense_template.pxi +3257 -0
- sage/matrix/matrix_modn_dense_template_header.pxi +15 -0
- sage/matrix/matrix_modn_sparse.pxd +8 -0
- sage/misc/all__sagemath_ntl.py +1 -0
- sage/rings/all__sagemath_ntl.py +7 -0
- sage/rings/bernmm.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/bernmm.pyx +161 -0
- sage/rings/bernoulli_mod_p.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/bernoulli_mod_p.pyx +313 -0
- sage/rings/finite_rings/all__sagemath_ntl.py +1 -0
- sage/rings/finite_rings/finite_field_ntl_gf2e.py +305 -0
- sage/rings/finite_rings/residue_field_ntl_gf2e.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/finite_rings/residue_field_ntl_gf2e.pyx +140 -0
- sage/rings/padics/all__sagemath_ntl.py +5 -0
- sage/rings/padics/padic_ZZ_pX_CA_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/padics/padic_ZZ_pX_CA_element.pxd +25 -0
- sage/rings/padics/padic_ZZ_pX_CA_element.pyx +2368 -0
- sage/rings/padics/padic_ZZ_pX_CR_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/padics/padic_ZZ_pX_CR_element.pxd +33 -0
- sage/rings/padics/padic_ZZ_pX_CR_element.pyx +3277 -0
- sage/rings/padics/padic_ZZ_pX_FM_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/padics/padic_ZZ_pX_FM_element.pxd +12 -0
- sage/rings/padics/padic_ZZ_pX_FM_element.pyx +1739 -0
- sage/rings/padics/padic_ZZ_pX_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/padics/padic_ZZ_pX_element.pxd +6 -0
- sage/rings/padics/padic_ZZ_pX_element.pyx +919 -0
- sage/rings/padics/padic_ext_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/padics/padic_ext_element.pxd +38 -0
- sage/rings/padics/padic_ext_element.pyx +512 -0
- sage/rings/padics/pow_computer_ext.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/padics/pow_computer_ext.pxd +107 -0
- sage/rings/padics/pow_computer_ext.pyx +2401 -0
- sage/rings/polynomial/all__sagemath_ntl.py +1 -0
- sage/rings/polynomial/evaluation_ntl.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/evaluation_ntl.pxd +7 -0
- sage/rings/polynomial/evaluation_ntl.pyx +70 -0
- sage/rings/polynomial/polynomial_gf2x.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_gf2x.pxd +10 -0
- sage/rings/polynomial/polynomial_gf2x.pyx +364 -0
- sage/rings/polynomial/polynomial_integer_dense_ntl.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_integer_dense_ntl.pxd +8 -0
- sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +1128 -0
- sage/rings/polynomial/polynomial_modn_dense_ntl.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_modn_dense_ntl.pxd +36 -0
- sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +2049 -0
- sage/rings/polynomial/polynomial_template.pxi +842 -0
- sage/rings/polynomial/polynomial_template_header.pxi +11 -0
- sage/rings/polynomial/polynomial_zz_pex.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_zz_pex.pxd +12 -0
- sage/rings/polynomial/polynomial_zz_pex.pyx +778 -0
- sage/rings/real_mpfi.pxd +50 -0
- sage/schemes/all__sagemath_ntl.py +1 -0
- sage/schemes/hyperelliptic_curves/all__sagemath_ntl.py +1 -0
- sage/schemes/hyperelliptic_curves/hypellfrob.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/schemes/hyperelliptic_curves/hypellfrob.pyx +252 -0
|
@@ -0,0 +1,1532 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-ntl
|
|
2
|
+
# distutils: libraries = NTL_LIBRARIES gmp M_LIBRARIES
|
|
3
|
+
# distutils: extra_compile_args = NTL_CFLAGS
|
|
4
|
+
# distutils: include_dirs = NTL_INCDIR
|
|
5
|
+
# distutils: library_dirs = NTL_LIBDIR
|
|
6
|
+
# distutils: extra_link_args = NTL_LIBEXTRA
|
|
7
|
+
# distutils: language = c++
|
|
8
|
+
|
|
9
|
+
# ****************************************************************************
|
|
10
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
11
|
+
#
|
|
12
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
13
|
+
#
|
|
14
|
+
# This code is distributed in the hope that it will be useful,
|
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
17
|
+
# General Public License for more details.
|
|
18
|
+
#
|
|
19
|
+
# The full text of the GPL is available at:
|
|
20
|
+
#
|
|
21
|
+
# https://www.gnu.org/licenses/
|
|
22
|
+
# ****************************************************************************
|
|
23
|
+
|
|
24
|
+
from cysignals.signals cimport sig_on, sig_off
|
|
25
|
+
from sage.ext.cplusplus cimport ccrepr, ccreadstr
|
|
26
|
+
|
|
27
|
+
include 'misc.pxi'
|
|
28
|
+
include 'decl.pxi'
|
|
29
|
+
|
|
30
|
+
from cpython.object cimport Py_EQ, Py_NE
|
|
31
|
+
from sage.cpython.string cimport char_to_str
|
|
32
|
+
from sage.rings.integer cimport Integer
|
|
33
|
+
from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ
|
|
34
|
+
from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p
|
|
35
|
+
from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class
|
|
36
|
+
from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext
|
|
37
|
+
from sage.libs.ntl.ntl_ZZ import unpickle_class_args
|
|
38
|
+
from sage.misc.randstate cimport current_randstate
|
|
39
|
+
from sage.libs.gmp.mpz cimport *
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
cdef inline make_ZZ_p(ZZ_p_c* x, ntl_ZZ_pContext_class ctx):
|
|
43
|
+
cdef ntl_ZZ_p y
|
|
44
|
+
sig_off()
|
|
45
|
+
y = ntl_ZZ_p(modulus = ctx)
|
|
46
|
+
y.x = x[0]
|
|
47
|
+
del x
|
|
48
|
+
return y
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
cdef make_ZZ_pX(ZZ_pX_c* x, ntl_ZZ_pContext_class ctx):
|
|
52
|
+
cdef ntl_ZZ_pX y
|
|
53
|
+
y = <ntl_ZZ_pX>ntl_ZZ_pX.__new__(ntl_ZZ_pX)
|
|
54
|
+
y.c = ctx
|
|
55
|
+
y.x = x[0]
|
|
56
|
+
del x
|
|
57
|
+
sig_off()
|
|
58
|
+
return y
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
##############################################################################
|
|
62
|
+
#
|
|
63
|
+
# ZZ_pX -- polynomials over the integers modulo p
|
|
64
|
+
#
|
|
65
|
+
##############################################################################
|
|
66
|
+
|
|
67
|
+
cdef class ntl_ZZ_pX():
|
|
68
|
+
r"""
|
|
69
|
+
The class \class{ZZ_pX} implements polynomial arithmetic modulo `p`.
|
|
70
|
+
|
|
71
|
+
Polynomial arithmetic is implemented using the FFT, combined with
|
|
72
|
+
the Chinese Remainder Theorem. A more detailed description of the
|
|
73
|
+
techniques used here can be found in [Shoup, J. Symbolic
|
|
74
|
+
Comp. 20:363-397, 1995].
|
|
75
|
+
|
|
76
|
+
Small degree polynomials are multiplied either with classical
|
|
77
|
+
or Karatsuba algorithms.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# See ntl_ZZ_pX.pxd for definition of data members
|
|
81
|
+
def __init__(self, v=None, modulus=None):
|
|
82
|
+
"""
|
|
83
|
+
EXAMPLES::
|
|
84
|
+
|
|
85
|
+
sage: c = ntl.ZZ_pContext(ntl.ZZ(20))
|
|
86
|
+
sage: f = ntl.ZZ_pX([1,2,5,-9], c)
|
|
87
|
+
sage: f
|
|
88
|
+
[1 2 5 11]
|
|
89
|
+
sage: g = ntl.ZZ_pX([0,0,0], c); g
|
|
90
|
+
[]
|
|
91
|
+
sage: g[10]=5
|
|
92
|
+
sage: g
|
|
93
|
+
[0 0 0 0 0 0 0 0 0 0 5]
|
|
94
|
+
sage: g[10]
|
|
95
|
+
5
|
|
96
|
+
"""
|
|
97
|
+
if modulus is None:
|
|
98
|
+
raise ValueError("You must specify a modulus when creating a ZZ_pX.")
|
|
99
|
+
|
|
100
|
+
# self.c._assert_is_current_modulus() # the context was restored in __new__
|
|
101
|
+
cdef ntl_ZZ_p cc
|
|
102
|
+
cdef Py_ssize_t i
|
|
103
|
+
|
|
104
|
+
if isinstance(v, ntl_ZZ_pX) and (<ntl_ZZ_pX>v).c is self.c:
|
|
105
|
+
self.x = (<ntl_ZZ_pX>v).x
|
|
106
|
+
elif isinstance(v, (list, tuple, xrange)):
|
|
107
|
+
for i, x in enumerate(v):
|
|
108
|
+
if not isinstance(x, ntl_ZZ_p):
|
|
109
|
+
cc = ntl_ZZ_p(x, self.c)
|
|
110
|
+
self.c.restore_c()
|
|
111
|
+
else:
|
|
112
|
+
cc = x
|
|
113
|
+
ZZ_pX_SetCoeff(self.x, i, cc.x)
|
|
114
|
+
elif v is not None:
|
|
115
|
+
s = str(v).replace(',', ' ').replace('L', '') # can change the modulus; Issue #25790
|
|
116
|
+
self.c.restore_c()
|
|
117
|
+
ccreadstr(self.x, s)
|
|
118
|
+
|
|
119
|
+
def __cinit__(self, v=None, modulus=None):
|
|
120
|
+
#################### WARNING ###################
|
|
121
|
+
## Before creating a ZZ_pX, you must create a ##
|
|
122
|
+
## ZZ_pContext, and restore it. In Python, ##
|
|
123
|
+
## the error checking in __init__ will prevent##
|
|
124
|
+
## you from constructing an ntl_ZZ_p ##
|
|
125
|
+
## inappropriately. However, from Cython, you##
|
|
126
|
+
## could do r = ntl_ZZ_p.__new__(ntl_ZZ_p) without
|
|
127
|
+
## first restoring a ZZ_pContext, which could ##
|
|
128
|
+
## have unfortunate consequences. See _new ##
|
|
129
|
+
## defined below for an example of the right ##
|
|
130
|
+
## way to short-circuit __init__ (or just call##
|
|
131
|
+
## _new in your own code). ##
|
|
132
|
+
################################################
|
|
133
|
+
if modulus is None:
|
|
134
|
+
return
|
|
135
|
+
if isinstance(modulus, ntl_ZZ_pContext_class):
|
|
136
|
+
self.c = <ntl_ZZ_pContext_class>modulus
|
|
137
|
+
self.c.restore_c()
|
|
138
|
+
elif modulus is not None:
|
|
139
|
+
self.c = <ntl_ZZ_pContext_class>ntl_ZZ_pContext(ntl_ZZ(modulus))
|
|
140
|
+
self.c.restore_c()
|
|
141
|
+
|
|
142
|
+
cdef ntl_ZZ_pX _new(self):
|
|
143
|
+
cdef ntl_ZZ_pX r
|
|
144
|
+
self.c.restore_c()
|
|
145
|
+
r = ntl_ZZ_pX.__new__(ntl_ZZ_pX)
|
|
146
|
+
r.c = self.c
|
|
147
|
+
return r
|
|
148
|
+
|
|
149
|
+
def __reduce__(self):
|
|
150
|
+
"""
|
|
151
|
+
TESTS::
|
|
152
|
+
|
|
153
|
+
sage: f = ntl.ZZ_pX([1,2,3,7], 5); f
|
|
154
|
+
[1 2 3 2]
|
|
155
|
+
sage: loads(dumps(f)) == f
|
|
156
|
+
True
|
|
157
|
+
"""
|
|
158
|
+
return unpickle_class_args, (ntl_ZZ_pX, (self.list(), self.get_modulus_context()))
|
|
159
|
+
|
|
160
|
+
def __repr__(self):
|
|
161
|
+
"""
|
|
162
|
+
Return the string representation of ``self``.
|
|
163
|
+
|
|
164
|
+
EXAMPLES::
|
|
165
|
+
|
|
166
|
+
sage: x = ntl.ZZ_pX([1,0,8],5)
|
|
167
|
+
sage: x
|
|
168
|
+
[1 0 3]
|
|
169
|
+
sage: x.__repr__()
|
|
170
|
+
'[1 0 3]'
|
|
171
|
+
"""
|
|
172
|
+
self.c.restore_c()
|
|
173
|
+
return ccrepr(self.x)
|
|
174
|
+
|
|
175
|
+
def __copy__(self):
|
|
176
|
+
"""
|
|
177
|
+
Return a copy of ``self``.
|
|
178
|
+
|
|
179
|
+
EXAMPLES::
|
|
180
|
+
|
|
181
|
+
sage: x = ntl.ZZ_pX([0,5,-3],11)
|
|
182
|
+
sage: y = copy(x)
|
|
183
|
+
sage: x == y
|
|
184
|
+
True
|
|
185
|
+
sage: x is y
|
|
186
|
+
False
|
|
187
|
+
sage: x[0] = 4; y
|
|
188
|
+
[0 5 8]
|
|
189
|
+
"""
|
|
190
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
191
|
+
#self.c.restore_c() # restored in _new()
|
|
192
|
+
r.x = self.x
|
|
193
|
+
return r
|
|
194
|
+
|
|
195
|
+
def get_modulus_context(self):
|
|
196
|
+
"""
|
|
197
|
+
Return the modulus for ``self``.
|
|
198
|
+
|
|
199
|
+
EXAMPLES::
|
|
200
|
+
|
|
201
|
+
sage: x = ntl.ZZ_pX([0,5,3],17)
|
|
202
|
+
sage: c = x.get_modulus_context()
|
|
203
|
+
sage: y = ntl.ZZ_pX([5],c)
|
|
204
|
+
sage: x+y
|
|
205
|
+
[5 5 3]
|
|
206
|
+
"""
|
|
207
|
+
return self.c
|
|
208
|
+
|
|
209
|
+
def __setitem__(self, long i, a):
|
|
210
|
+
r"""
|
|
211
|
+
EXAMPLES::
|
|
212
|
+
|
|
213
|
+
sage: c = ntl.ZZ_pContext(23)
|
|
214
|
+
sage: x = ntl.ZZ_pX([2, 3, 4], c)
|
|
215
|
+
sage: x[1] = 5
|
|
216
|
+
sage: x
|
|
217
|
+
[2 5 4]
|
|
218
|
+
"""
|
|
219
|
+
if i < 0:
|
|
220
|
+
raise IndexError("index (i=%s) must be >= 0" % i)
|
|
221
|
+
cdef ntl_ZZ_p _a
|
|
222
|
+
_a = ntl_ZZ_p(a,self.c)
|
|
223
|
+
self.c.restore_c()
|
|
224
|
+
ZZ_pX_SetCoeff(self.x, i, _a.x)
|
|
225
|
+
|
|
226
|
+
cdef void setitem_from_int(ntl_ZZ_pX self, long i, int value) noexcept:
|
|
227
|
+
r"""
|
|
228
|
+
Set `i`-th coefficient to value.
|
|
229
|
+
|
|
230
|
+
AUTHOR: David Harvey (2006-08-05)
|
|
231
|
+
"""
|
|
232
|
+
self.c.restore_c()
|
|
233
|
+
ZZ_pX_SetCoeff_long(self.x, i, value)
|
|
234
|
+
|
|
235
|
+
def _setitem_from_int_doctest(self, i, value):
|
|
236
|
+
r"""
|
|
237
|
+
This method exists solely for automated testing of setitem_from_int().
|
|
238
|
+
|
|
239
|
+
TESTS::
|
|
240
|
+
|
|
241
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
242
|
+
sage: x = ntl.ZZ_pX([2, 3, 4], c)
|
|
243
|
+
sage: x._setitem_from_int_doctest(5, 42)
|
|
244
|
+
sage: x
|
|
245
|
+
[2 3 4 0 0 2]
|
|
246
|
+
"""
|
|
247
|
+
self.c.restore_c()
|
|
248
|
+
self.setitem_from_int(i, value)
|
|
249
|
+
|
|
250
|
+
def __getitem__(self, long i):
|
|
251
|
+
r"""
|
|
252
|
+
Return the `i`-th entry of ``self``.
|
|
253
|
+
|
|
254
|
+
EXAMPLES::
|
|
255
|
+
|
|
256
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
257
|
+
sage: x = ntl.ZZ_pX([2, 3, 4], c)
|
|
258
|
+
sage: x[1]
|
|
259
|
+
3
|
|
260
|
+
"""
|
|
261
|
+
cdef ntl_ZZ_p r
|
|
262
|
+
r = ntl_ZZ_p.__new__(ntl_ZZ_p)
|
|
263
|
+
r.c = self.c
|
|
264
|
+
self.c.restore_c()
|
|
265
|
+
if i < 0:
|
|
266
|
+
r.set_from_int(0)
|
|
267
|
+
else:
|
|
268
|
+
r.x = ZZ_pX_coeff( self.x, i)
|
|
269
|
+
return r
|
|
270
|
+
|
|
271
|
+
cdef int getitem_as_int(ntl_ZZ_pX self, long i) noexcept:
|
|
272
|
+
r"""
|
|
273
|
+
Return `i`-th coefficient as C int.
|
|
274
|
+
|
|
275
|
+
Return value is only valid if the result fits into an int.
|
|
276
|
+
|
|
277
|
+
AUTHOR: David Harvey (2006-08-05)
|
|
278
|
+
"""
|
|
279
|
+
self.c.restore_c()
|
|
280
|
+
cdef ZZ_p_c r
|
|
281
|
+
cdef long l = 0
|
|
282
|
+
sig_on()
|
|
283
|
+
r = ZZ_pX_coeff( self.x, i)
|
|
284
|
+
ZZ_conv_to_long(l, ZZ_p_rep(r))
|
|
285
|
+
sig_off()
|
|
286
|
+
return l
|
|
287
|
+
|
|
288
|
+
def _getitem_as_int_doctest(self, i):
|
|
289
|
+
r"""
|
|
290
|
+
This method exists solely for automated testing of getitem_as_int().
|
|
291
|
+
|
|
292
|
+
TESTS::
|
|
293
|
+
|
|
294
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
295
|
+
sage: x = ntl.ZZ_pX([2, 3, 5, -7, 11], c)
|
|
296
|
+
sage: i = x._getitem_as_int_doctest(3)
|
|
297
|
+
sage: i
|
|
298
|
+
13
|
|
299
|
+
sage: type(i)
|
|
300
|
+
<... 'int'>
|
|
301
|
+
sage: x._getitem_as_int_doctest(15)
|
|
302
|
+
0
|
|
303
|
+
"""
|
|
304
|
+
# self.c.restore_c() # restored in getitem_as_int()
|
|
305
|
+
return self.getitem_as_int(i)
|
|
306
|
+
|
|
307
|
+
def list(self):
|
|
308
|
+
"""
|
|
309
|
+
Return list of entries as a list of ntl_ZZ_p.
|
|
310
|
+
|
|
311
|
+
EXAMPLES::
|
|
312
|
+
|
|
313
|
+
sage: x = ntl.ZZ_pX([1,3,5],11)
|
|
314
|
+
sage: x.list()
|
|
315
|
+
[1, 3, 5]
|
|
316
|
+
sage: type(x.list()[0])
|
|
317
|
+
<class 'sage.libs.ntl.ntl_ZZ_p.ntl_ZZ_p'>
|
|
318
|
+
"""
|
|
319
|
+
# could be sped up.
|
|
320
|
+
self.c.restore_c()
|
|
321
|
+
cdef Py_ssize_t i
|
|
322
|
+
return [self[i] for i from 0 <= i <= self.degree()]
|
|
323
|
+
|
|
324
|
+
def __add__(ntl_ZZ_pX self, ntl_ZZ_pX other):
|
|
325
|
+
"""
|
|
326
|
+
EXAMPLES::
|
|
327
|
+
|
|
328
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
329
|
+
sage: ntl.ZZ_pX(range(5),c) + ntl.ZZ_pX(range(6),c)
|
|
330
|
+
[0 2 4 6 8 5]
|
|
331
|
+
"""
|
|
332
|
+
if self.c is not other.c:
|
|
333
|
+
raise ValueError("You cannot perform arithmetic with elements of different moduli.")
|
|
334
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
335
|
+
sig_on()
|
|
336
|
+
#self.c.restore_c() # restored in _new()
|
|
337
|
+
ZZ_pX_add(r.x, self.x, other.x)
|
|
338
|
+
sig_off()
|
|
339
|
+
return r
|
|
340
|
+
|
|
341
|
+
def __sub__(ntl_ZZ_pX self, ntl_ZZ_pX other):
|
|
342
|
+
"""
|
|
343
|
+
EXAMPLES::
|
|
344
|
+
|
|
345
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
346
|
+
sage: ntl.ZZ_pX(range(5),c) - ntl.ZZ_pX(range(6),c)
|
|
347
|
+
[0 0 0 0 0 15]
|
|
348
|
+
"""
|
|
349
|
+
if self.c is not other.c:
|
|
350
|
+
raise ValueError("You cannot perform arithmetic with elements of different moduli.")
|
|
351
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
352
|
+
sig_on()
|
|
353
|
+
#self.c.restore_c() # restored in _new()
|
|
354
|
+
ZZ_pX_sub(r.x, self.x, other.x)
|
|
355
|
+
sig_off()
|
|
356
|
+
return r
|
|
357
|
+
|
|
358
|
+
def __mul__(ntl_ZZ_pX self, ntl_ZZ_pX other):
|
|
359
|
+
"""
|
|
360
|
+
EXAMPLES::
|
|
361
|
+
|
|
362
|
+
sage: c1 = ntl.ZZ_pContext(20)
|
|
363
|
+
sage: alpha = ntl.ZZ_pX(range(5), c1)
|
|
364
|
+
sage: beta = ntl.ZZ_pX(range(6), c1)
|
|
365
|
+
sage: alpha * beta
|
|
366
|
+
[0 0 1 4 10 0 10 14 11]
|
|
367
|
+
sage: c2 = ntl.ZZ_pContext(ntl.ZZ(5)) # we can mix up the moduli
|
|
368
|
+
sage: x = ntl.ZZ_pX([2, 3, 4], c2)
|
|
369
|
+
sage: x^2
|
|
370
|
+
[4 2 0 4 1]
|
|
371
|
+
sage: alpha * beta # back to the first one and the ntl modulus gets reset correctly
|
|
372
|
+
[0 0 1 4 10 0 10 14 11]
|
|
373
|
+
"""
|
|
374
|
+
if self.c is not other.c:
|
|
375
|
+
raise ValueError("You cannot perform arithmetic with elements of different moduli.")
|
|
376
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
377
|
+
sig_on()
|
|
378
|
+
# self.c.restore_c() # restored in _new()
|
|
379
|
+
ZZ_pX_mul(r.x, self.x, other.x)
|
|
380
|
+
sig_off()
|
|
381
|
+
return r
|
|
382
|
+
|
|
383
|
+
def __truediv__(ntl_ZZ_pX self, ntl_ZZ_pX other):
|
|
384
|
+
"""
|
|
385
|
+
Compute quotient ``self / other``, if the quotient is a polynomial.
|
|
386
|
+
Otherwise an Exception is raised.
|
|
387
|
+
|
|
388
|
+
EXAMPLES::
|
|
389
|
+
|
|
390
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
391
|
+
sage: f = ntl.ZZ_pX([1,2,3], c) * ntl.ZZ_pX([4,5], c)**2
|
|
392
|
+
sage: g = ntl.ZZ_pX([4,5], c)
|
|
393
|
+
sage: f/g
|
|
394
|
+
[4 13 5 15]
|
|
395
|
+
sage: ntl.ZZ_pX([1,2,3],c) * ntl.ZZ_pX([4,5],c)
|
|
396
|
+
[4 13 5 15]
|
|
397
|
+
|
|
398
|
+
sage: f = ntl.ZZ_pX(range(10), c); g = ntl.ZZ_pX([-1,0,1], c)
|
|
399
|
+
sage: f/g
|
|
400
|
+
Traceback (most recent call last):
|
|
401
|
+
...
|
|
402
|
+
ArithmeticError: self (=[0 1 2 3 4 5 6 7 8 9]) is not divisible by other (=[16 0 1])
|
|
403
|
+
"""
|
|
404
|
+
if self.c is not other.c:
|
|
405
|
+
raise ValueError("You cannot perform arithmetic with elements of different moduli.")
|
|
406
|
+
cdef int divisible
|
|
407
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
408
|
+
sig_on()
|
|
409
|
+
#self.c.restore_c() # restored in _new()
|
|
410
|
+
divisible = ZZ_pX_divide(r.x, self.x, other.x)
|
|
411
|
+
sig_off()
|
|
412
|
+
if not divisible:
|
|
413
|
+
raise ArithmeticError("self (=%s) is not divisible by other (=%s)" % (self, other))
|
|
414
|
+
return r
|
|
415
|
+
|
|
416
|
+
def __mod__(ntl_ZZ_pX self, ntl_ZZ_pX other):
|
|
417
|
+
"""
|
|
418
|
+
Given polynomials a, b in ZZ_p[X], if p is prime, then there exist polynomials q, r
|
|
419
|
+
in ZZ_p[X] such that a = b*q + r, deg(r) < deg(b). This
|
|
420
|
+
function returns r.
|
|
421
|
+
|
|
422
|
+
If p is not prime this function may raise a :exc:`RuntimeError`
|
|
423
|
+
due to division by a noninvertible element of ZZ_p.
|
|
424
|
+
|
|
425
|
+
EXAMPLES::
|
|
426
|
+
|
|
427
|
+
sage: c = ntl.ZZ_pContext(ntl.ZZ(17))
|
|
428
|
+
sage: f = ntl.ZZ_pX([2,4,6], c); g = ntl.ZZ_pX([2], c)
|
|
429
|
+
sage: f % g # 0
|
|
430
|
+
[]
|
|
431
|
+
sage: f = ntl.ZZ_pX(range(10), c); g = ntl.ZZ_pX([-1,0,1], c)
|
|
432
|
+
sage: f % g
|
|
433
|
+
[3 8]
|
|
434
|
+
|
|
435
|
+
sage: c = ntl.ZZ_pContext(ntl.ZZ(16))
|
|
436
|
+
sage: f = ntl.ZZ_pX([2,4,6], c); g = ntl.ZZ_pX([2], c)
|
|
437
|
+
sage: f % g
|
|
438
|
+
Traceback (most recent call last):
|
|
439
|
+
...
|
|
440
|
+
NTLError: ZZ_p: division by non-invertible element
|
|
441
|
+
"""
|
|
442
|
+
if self.c is not other.c:
|
|
443
|
+
raise ValueError("You cannot perform arithmetic with elements of different moduli.")
|
|
444
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
445
|
+
sig_on()
|
|
446
|
+
#self.c.restore_c() # restored in _new()
|
|
447
|
+
ZZ_pX_rem(r.x, self.x, other.x)
|
|
448
|
+
sig_off()
|
|
449
|
+
return r
|
|
450
|
+
|
|
451
|
+
def quo_rem(self, ntl_ZZ_pX other):
|
|
452
|
+
"""
|
|
453
|
+
Return the unique integral `q` and `r` such that ``self = q*other +
|
|
454
|
+
r``, if they exist. Otherwise raises an Exception.
|
|
455
|
+
|
|
456
|
+
EXAMPLES::
|
|
457
|
+
|
|
458
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
459
|
+
sage: f = ntl.ZZ_pX(range(10), c); g = ntl.ZZ_pX([-1,0,1], c)
|
|
460
|
+
sage: q, r = f.quo_rem(g)
|
|
461
|
+
sage: q, r
|
|
462
|
+
([3 7 1 4 14 16 8 9], [3 8])
|
|
463
|
+
sage: q*g + r == f
|
|
464
|
+
True
|
|
465
|
+
"""
|
|
466
|
+
if self.c is not other.c:
|
|
467
|
+
raise ValueError("You cannot perform arithmetic with elements of different moduli.")
|
|
468
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
469
|
+
cdef ntl_ZZ_pX q = self._new()
|
|
470
|
+
sig_on()
|
|
471
|
+
#self.c.restore_c() # restored in _new()
|
|
472
|
+
ZZ_pX_DivRem(q.x, r.x, self.x, other.x)
|
|
473
|
+
sig_off()
|
|
474
|
+
return q,r
|
|
475
|
+
|
|
476
|
+
def square(self):
|
|
477
|
+
"""
|
|
478
|
+
Return f*f.
|
|
479
|
+
|
|
480
|
+
EXAMPLES::
|
|
481
|
+
|
|
482
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
483
|
+
sage: f = ntl.ZZ_pX([-1,0,1], c)
|
|
484
|
+
sage: f*f
|
|
485
|
+
[1 0 15 0 1]
|
|
486
|
+
"""
|
|
487
|
+
#self.c.restore_c() # restored in _new()
|
|
488
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
489
|
+
sig_on()
|
|
490
|
+
ZZ_pX_sqr(r.x, self.x)
|
|
491
|
+
sig_off()
|
|
492
|
+
return r
|
|
493
|
+
|
|
494
|
+
def __pow__(self, n, modulus):
|
|
495
|
+
"""
|
|
496
|
+
Return the ``n``-th nonnegative power of ``self``.
|
|
497
|
+
|
|
498
|
+
If ``modulus`` is not ``None``, the exponentiation is performed
|
|
499
|
+
modulo the polynomial ``modulus``.
|
|
500
|
+
|
|
501
|
+
EXAMPLES::
|
|
502
|
+
|
|
503
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
504
|
+
sage: g = ntl.ZZ_pX([-1,0,1],c)
|
|
505
|
+
sage: g**10
|
|
506
|
+
[1 0 10 0 5 0 0 0 10 0 8 0 10 0 0 0 5 0 10 0 1]
|
|
507
|
+
|
|
508
|
+
sage: x = ntl.ZZ_pX([0,1],c)
|
|
509
|
+
sage: x**10
|
|
510
|
+
[0 0 0 0 0 0 0 0 0 0 1]
|
|
511
|
+
|
|
512
|
+
Modular exponentiation::
|
|
513
|
+
|
|
514
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
515
|
+
sage: f = ntl.ZZ_pX([1,0,1],c)
|
|
516
|
+
sage: m = ntl.ZZ_pX([1,0,0,0,0,1],c)
|
|
517
|
+
sage: pow(f, 123**45, m)
|
|
518
|
+
[1 19 3 0 3]
|
|
519
|
+
|
|
520
|
+
Modular exponentiation of ``x``::
|
|
521
|
+
|
|
522
|
+
sage: f = ntl.ZZ_pX([0,1],c)
|
|
523
|
+
sage: f.is_x()
|
|
524
|
+
True
|
|
525
|
+
sage: m = ntl.ZZ_pX([1,1,0,0,0,1],c)
|
|
526
|
+
sage: pow(f, 123**45, m)
|
|
527
|
+
[15 5 5 11]
|
|
528
|
+
"""
|
|
529
|
+
if modulus is None:
|
|
530
|
+
return (<ntl_ZZ_pX>self)._pow(n)
|
|
531
|
+
else:
|
|
532
|
+
return (<ntl_ZZ_pX>self)._powmod(Integer(n), modulus)
|
|
533
|
+
|
|
534
|
+
cdef ntl_ZZ_pX _pow(ntl_ZZ_pX self, long n):
|
|
535
|
+
"""
|
|
536
|
+
Compute the ``n``-th power of ``self``.
|
|
537
|
+
"""
|
|
538
|
+
if n < 0:
|
|
539
|
+
raise NotImplementedError
|
|
540
|
+
cdef long ln = n
|
|
541
|
+
#self.c.restore_c() # restored in _new()
|
|
542
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
543
|
+
if self.is_x() and n >= 1:
|
|
544
|
+
ZZ_pX_LeftShift(r.x, self.x, n-1)
|
|
545
|
+
else:
|
|
546
|
+
sig_on()
|
|
547
|
+
ZZ_pX_power(r.x, self.x, ln)
|
|
548
|
+
sig_off()
|
|
549
|
+
return r
|
|
550
|
+
|
|
551
|
+
cdef ntl_ZZ_pX _powmod(ntl_ZZ_pX self, Integer n, ntl_ZZ_pX modulus):
|
|
552
|
+
r"""
|
|
553
|
+
Compute the ``n``-th power of ``self`` modulo a polynomial.
|
|
554
|
+
"""
|
|
555
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
556
|
+
cdef ZZ_c n_ZZ
|
|
557
|
+
cdef ZZ_pX_Modulus_c mod
|
|
558
|
+
is_x = self.is_x()
|
|
559
|
+
sig_on()
|
|
560
|
+
mpz_to_ZZ(&n_ZZ, (<Integer>n).value)
|
|
561
|
+
ZZ_pX_Modulus_build(mod, modulus.x)
|
|
562
|
+
if is_x:
|
|
563
|
+
ZZ_pX_PowerXMod_pre(r.x, n_ZZ, mod)
|
|
564
|
+
else:
|
|
565
|
+
ZZ_pX_PowerMod_pre(r.x, self.x, n_ZZ, mod)
|
|
566
|
+
sig_off()
|
|
567
|
+
return r
|
|
568
|
+
|
|
569
|
+
def __richcmp__(ntl_ZZ_pX self, other, int op):
|
|
570
|
+
"""
|
|
571
|
+
Compare ``self`` to ``other``.
|
|
572
|
+
|
|
573
|
+
EXAMPLES::
|
|
574
|
+
|
|
575
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
576
|
+
sage: f = ntl.ZZ_pX([1,2,3],c)
|
|
577
|
+
sage: g = ntl.ZZ_pX([1,2,3,0],c)
|
|
578
|
+
sage: f == g
|
|
579
|
+
True
|
|
580
|
+
sage: g = ntl.ZZ_pX([0,1,2,3],c)
|
|
581
|
+
sage: f != g
|
|
582
|
+
True
|
|
583
|
+
sage: f != 0
|
|
584
|
+
True
|
|
585
|
+
"""
|
|
586
|
+
self.c.restore_c()
|
|
587
|
+
|
|
588
|
+
if op != Py_EQ and op != Py_NE:
|
|
589
|
+
raise TypeError("polynomials are not ordered")
|
|
590
|
+
|
|
591
|
+
cdef ntl_ZZ_pX b
|
|
592
|
+
try:
|
|
593
|
+
b = <ntl_ZZ_pX?>other
|
|
594
|
+
except TypeError:
|
|
595
|
+
b = ntl_ZZ_pX(other, self.c)
|
|
596
|
+
|
|
597
|
+
return (op == Py_EQ) == (self.x == b.x)
|
|
598
|
+
|
|
599
|
+
def is_zero(self):
|
|
600
|
+
"""
|
|
601
|
+
Return ``True`` exactly if this polynomial is 0.
|
|
602
|
+
|
|
603
|
+
EXAMPLES::
|
|
604
|
+
|
|
605
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
606
|
+
sage: f = ntl.ZZ_pX([0,0,0,20],c)
|
|
607
|
+
sage: f.is_zero()
|
|
608
|
+
True
|
|
609
|
+
sage: f = ntl.ZZ_pX([0,0,1],c)
|
|
610
|
+
sage: f
|
|
611
|
+
[0 0 1]
|
|
612
|
+
sage: f.is_zero()
|
|
613
|
+
False
|
|
614
|
+
"""
|
|
615
|
+
self.c.restore_c()
|
|
616
|
+
return bool(ZZ_pX_IsZero(self.x))
|
|
617
|
+
|
|
618
|
+
def is_one(self):
|
|
619
|
+
"""
|
|
620
|
+
Return ``True`` exactly if this polynomial is 1.
|
|
621
|
+
|
|
622
|
+
EXAMPLES::
|
|
623
|
+
|
|
624
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
625
|
+
sage: f = ntl.ZZ_pX([1,1],c)
|
|
626
|
+
sage: f.is_one()
|
|
627
|
+
False
|
|
628
|
+
sage: f = ntl.ZZ_pX([1],c)
|
|
629
|
+
sage: f.is_one()
|
|
630
|
+
True
|
|
631
|
+
"""
|
|
632
|
+
self.c.restore_c()
|
|
633
|
+
return bool(ZZ_pX_IsOne(self.x))
|
|
634
|
+
|
|
635
|
+
def is_monic(self):
|
|
636
|
+
"""
|
|
637
|
+
Return ``True`` exactly if this polynomial is monic.
|
|
638
|
+
|
|
639
|
+
EXAMPLES::
|
|
640
|
+
|
|
641
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
642
|
+
sage: f = ntl.ZZ_pX([2,0,0,1],c)
|
|
643
|
+
sage: f.is_monic()
|
|
644
|
+
True
|
|
645
|
+
sage: g = f.reverse()
|
|
646
|
+
sage: g.is_monic()
|
|
647
|
+
False
|
|
648
|
+
sage: g
|
|
649
|
+
[1 0 0 2]
|
|
650
|
+
sage: f = ntl.ZZ_pX([1,2,0,3,0,2],c)
|
|
651
|
+
sage: f.is_monic()
|
|
652
|
+
False
|
|
653
|
+
"""
|
|
654
|
+
self.c.restore_c()
|
|
655
|
+
if ZZ_pX_IsZero(self.x):
|
|
656
|
+
return False
|
|
657
|
+
return bool(ZZ_p_IsOne(ZZ_pX_LeadCoeff(self.x)))
|
|
658
|
+
|
|
659
|
+
def __neg__(self):
|
|
660
|
+
"""
|
|
661
|
+
Return the negative of ``self``.
|
|
662
|
+
|
|
663
|
+
EXAMPLES::
|
|
664
|
+
|
|
665
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
666
|
+
sage: f = ntl.ZZ_pX([2,0,0,1],c)
|
|
667
|
+
sage: -f
|
|
668
|
+
[18 0 0 19]
|
|
669
|
+
"""
|
|
670
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
671
|
+
self.c.restore_c()
|
|
672
|
+
ZZ_pX_negate(r.x, self.x)
|
|
673
|
+
return r
|
|
674
|
+
|
|
675
|
+
def left_shift(self, long n):
|
|
676
|
+
"""
|
|
677
|
+
Return the polynomial obtained by shifting all coefficients of
|
|
678
|
+
this polynomial to the left n positions.
|
|
679
|
+
|
|
680
|
+
EXAMPLES::
|
|
681
|
+
|
|
682
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
683
|
+
sage: f = ntl.ZZ_pX([2,0,0,1],c)
|
|
684
|
+
sage: f
|
|
685
|
+
[2 0 0 1]
|
|
686
|
+
sage: f.left_shift(2)
|
|
687
|
+
[0 0 2 0 0 1]
|
|
688
|
+
sage: f.left_shift(5)
|
|
689
|
+
[0 0 0 0 0 2 0 0 1]
|
|
690
|
+
|
|
691
|
+
A negative left shift is a right shift.
|
|
692
|
+
sage: f.left_shift(-2)
|
|
693
|
+
[0 1]
|
|
694
|
+
"""
|
|
695
|
+
#self.c.restore_c() # restored in _new()
|
|
696
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
697
|
+
sig_on()
|
|
698
|
+
ZZ_pX_LeftShift(r.x, self.x, n)
|
|
699
|
+
sig_off()
|
|
700
|
+
return r
|
|
701
|
+
|
|
702
|
+
def right_shift(self, long n):
|
|
703
|
+
"""
|
|
704
|
+
Return the polynomial obtained by shifting all coefficients of
|
|
705
|
+
this polynomial to the right n positions.
|
|
706
|
+
|
|
707
|
+
EXAMPLES::
|
|
708
|
+
|
|
709
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
710
|
+
sage: f = ntl.ZZ_pX([2,0,0,1],c)
|
|
711
|
+
sage: f
|
|
712
|
+
[2 0 0 1]
|
|
713
|
+
sage: f.right_shift(2)
|
|
714
|
+
[0 1]
|
|
715
|
+
sage: f.right_shift(5)
|
|
716
|
+
[]
|
|
717
|
+
sage: f.right_shift(-2)
|
|
718
|
+
[0 0 2 0 0 1]
|
|
719
|
+
"""
|
|
720
|
+
#self.c.restore_c() # restored in _new()
|
|
721
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
722
|
+
sig_on()
|
|
723
|
+
ZZ_pX_RightShift(r.x, self.x, n)
|
|
724
|
+
sig_off()
|
|
725
|
+
return r
|
|
726
|
+
|
|
727
|
+
def _left_pshift(self, ntl_ZZ n):
|
|
728
|
+
"""
|
|
729
|
+
Multiply all coefficients by `n` and the context by `n`.
|
|
730
|
+
"""
|
|
731
|
+
cdef ntl_ZZ new_c_p = ntl_ZZ.__new__(ntl_ZZ)
|
|
732
|
+
ZZ_mul(new_c_p.x, (<ntl_ZZ>self.c.p).x, n.x)
|
|
733
|
+
cdef ntl_ZZ_pContext_class new_c = <ntl_ZZ_pContext_class>ntl_ZZ_pContext(new_c_p)
|
|
734
|
+
new_c.restore_c()
|
|
735
|
+
cdef ntl_ZZ_pX ans = ntl_ZZ_pX.__new__(ntl_ZZ_pX)
|
|
736
|
+
ans.c = new_c
|
|
737
|
+
ZZ_pX_left_pshift(ans.x, self.x, n.x, new_c.x)
|
|
738
|
+
return ans
|
|
739
|
+
|
|
740
|
+
def _right_pshift(self, ntl_ZZ n):
|
|
741
|
+
"""
|
|
742
|
+
Divide all coefficients by `n` and the context by `n`. Only really
|
|
743
|
+
makes sense when `n` divides ``self.c.p``.
|
|
744
|
+
"""
|
|
745
|
+
cdef ntl_ZZ new_c_p = ntl_ZZ.__new__(ntl_ZZ)
|
|
746
|
+
ZZ_div(new_c_p.x, (<ntl_ZZ>self.c.p).x, n.x)
|
|
747
|
+
cdef ntl_ZZ_pContext_class new_c = <ntl_ZZ_pContext_class>ntl_ZZ_pContext(new_c_p)
|
|
748
|
+
new_c.restore_c()
|
|
749
|
+
cdef ntl_ZZ_pX ans = ntl_ZZ_pX.__new__(ntl_ZZ_pX)
|
|
750
|
+
ans.c = new_c
|
|
751
|
+
ZZ_pX_right_pshift(ans.x, self.x, n.x, new_c.x)
|
|
752
|
+
return ans
|
|
753
|
+
|
|
754
|
+
def gcd(self, ntl_ZZ_pX other):
|
|
755
|
+
"""
|
|
756
|
+
Return the gcd d = gcd(a, b), where by convention the leading coefficient
|
|
757
|
+
of d is >= 0. We uses a multi-modular algorithm.
|
|
758
|
+
|
|
759
|
+
EXAMPLES::
|
|
760
|
+
|
|
761
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
762
|
+
sage: f = ntl.ZZ_pX([1,2,3],c) * ntl.ZZ_pX([4,5],c)**2
|
|
763
|
+
sage: g = ntl.ZZ_pX([1,1,1],c)**3 * ntl.ZZ_pX([1,2,3],c)
|
|
764
|
+
sage: f.gcd(g)
|
|
765
|
+
[6 12 1]
|
|
766
|
+
sage: g.gcd(f)
|
|
767
|
+
[6 12 1]
|
|
768
|
+
"""
|
|
769
|
+
#self.c.restore_c() # restored in _new()
|
|
770
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
771
|
+
sig_on()
|
|
772
|
+
ZZ_pX_GCD(r.x, self.x, other.x)
|
|
773
|
+
sig_off()
|
|
774
|
+
return r
|
|
775
|
+
|
|
776
|
+
def xgcd(self, ntl_ZZ_pX other, plain=True):
|
|
777
|
+
"""
|
|
778
|
+
Return `r`, `s`, `t` such that ``r = s*self + t*other``.
|
|
779
|
+
|
|
780
|
+
Here r is the resultant of a and b; if r != 0, then this
|
|
781
|
+
function computes s and t such that: a*s + b*t = r; otherwise
|
|
782
|
+
s and t are both 0.
|
|
783
|
+
|
|
784
|
+
EXAMPLES::
|
|
785
|
+
|
|
786
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
787
|
+
sage: f = ntl.ZZ_pX([1,2,3],c) * ntl.ZZ_pX([4,5],c)**2
|
|
788
|
+
sage: g = ntl.ZZ_pX([1,1,1],c)**3 * ntl.ZZ_pX([1,2,3],c)
|
|
789
|
+
sage: f.xgcd(g) # nothing since they are not coprime
|
|
790
|
+
([6 12 1], [15 13 6 8 7 9], [4 13])
|
|
791
|
+
|
|
792
|
+
In this example the input quadratic polynomials have a common
|
|
793
|
+
root modulo 13::
|
|
794
|
+
|
|
795
|
+
sage: f = ntl.ZZ_pX([5,0,1],c)
|
|
796
|
+
sage: g = ntl.ZZ_pX([18,0,1],c)
|
|
797
|
+
sage: f.xgcd(g)
|
|
798
|
+
([1], [13], [4])
|
|
799
|
+
"""
|
|
800
|
+
self.c.restore_c()
|
|
801
|
+
cdef ntl_ZZ_pX s = self._new()
|
|
802
|
+
cdef ntl_ZZ_pX t = self._new()
|
|
803
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
804
|
+
sig_on()
|
|
805
|
+
if plain:
|
|
806
|
+
ZZ_pX_PlainXGCD(r.x, s.x, t.x, self.x, other.x)
|
|
807
|
+
else:
|
|
808
|
+
ZZ_pX_XGCD(r.x, s.x, t.x, self.x, other.x)
|
|
809
|
+
sig_off()
|
|
810
|
+
return (r,s,t)
|
|
811
|
+
|
|
812
|
+
def degree(self):
|
|
813
|
+
"""
|
|
814
|
+
Return the degree of this polynomial. The degree of the 0
|
|
815
|
+
polynomial is -1.
|
|
816
|
+
|
|
817
|
+
EXAMPLES::
|
|
818
|
+
|
|
819
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
820
|
+
sage: f = ntl.ZZ_pX([5,0,1],c)
|
|
821
|
+
sage: f.degree()
|
|
822
|
+
2
|
|
823
|
+
sage: f = ntl.ZZ_pX(range(100),c)
|
|
824
|
+
sage: f.degree()
|
|
825
|
+
99
|
|
826
|
+
sage: f = ntl.ZZ_pX([], c)
|
|
827
|
+
sage: f.degree()
|
|
828
|
+
-1
|
|
829
|
+
sage: f = ntl.ZZ_pX([1],c)
|
|
830
|
+
sage: f.degree()
|
|
831
|
+
0
|
|
832
|
+
"""
|
|
833
|
+
self.c.restore_c()
|
|
834
|
+
return ZZ_pX_deg(self.x)
|
|
835
|
+
|
|
836
|
+
def leading_coefficient(self):
|
|
837
|
+
"""
|
|
838
|
+
Return the leading coefficient of this polynomial.
|
|
839
|
+
|
|
840
|
+
EXAMPLES::
|
|
841
|
+
|
|
842
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
843
|
+
sage: f = ntl.ZZ_pX([3,6,9],c)
|
|
844
|
+
sage: f.leading_coefficient()
|
|
845
|
+
9
|
|
846
|
+
sage: f = ntl.ZZ_pX([],c)
|
|
847
|
+
sage: f.leading_coefficient()
|
|
848
|
+
0
|
|
849
|
+
"""
|
|
850
|
+
self.c.restore_c()
|
|
851
|
+
#return ZZ_pX_LeadCoeff(self.x)
|
|
852
|
+
cdef long i
|
|
853
|
+
i = ZZ_pX_deg(self.x)
|
|
854
|
+
return self[i]
|
|
855
|
+
|
|
856
|
+
def constant_term(self):
|
|
857
|
+
"""
|
|
858
|
+
Return the constant coefficient of this polynomial.
|
|
859
|
+
|
|
860
|
+
EXAMPLES::
|
|
861
|
+
|
|
862
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
863
|
+
sage: f = ntl.ZZ_pX([3,6,9],c)
|
|
864
|
+
sage: f.constant_term()
|
|
865
|
+
3
|
|
866
|
+
sage: f = ntl.ZZ_pX([],c)
|
|
867
|
+
sage: f.constant_term()
|
|
868
|
+
0
|
|
869
|
+
"""
|
|
870
|
+
self.c.restore_c()
|
|
871
|
+
#return ZZ_pX_ConstTerm(self.x)
|
|
872
|
+
return self[0]
|
|
873
|
+
|
|
874
|
+
def set_x(self):
|
|
875
|
+
"""
|
|
876
|
+
Set this polynomial to the monomial "x".
|
|
877
|
+
|
|
878
|
+
EXAMPLES::
|
|
879
|
+
|
|
880
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
881
|
+
sage: f = ntl.ZZ_pX([],c)
|
|
882
|
+
sage: f.set_x()
|
|
883
|
+
sage: f
|
|
884
|
+
[0 1]
|
|
885
|
+
sage: g = ntl.ZZ_pX([0,1],c)
|
|
886
|
+
sage: f == g
|
|
887
|
+
True
|
|
888
|
+
|
|
889
|
+
Though f and g are equal, they are not the same objects in memory::
|
|
890
|
+
|
|
891
|
+
sage: f is g
|
|
892
|
+
False
|
|
893
|
+
"""
|
|
894
|
+
self.c.restore_c()
|
|
895
|
+
ZZ_pX_SetX(self.x)
|
|
896
|
+
#ZZ_pX_clear(self.x)
|
|
897
|
+
#ZZ_pX_SetCoeff_long(self.x, 1, 1)
|
|
898
|
+
|
|
899
|
+
def is_x(self):
|
|
900
|
+
"""
|
|
901
|
+
``True`` if this is the polynomial "x".
|
|
902
|
+
|
|
903
|
+
EXAMPLES::
|
|
904
|
+
|
|
905
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
906
|
+
sage: f = ntl.ZZ_pX([],c)
|
|
907
|
+
sage: f.set_x()
|
|
908
|
+
sage: f.is_x()
|
|
909
|
+
True
|
|
910
|
+
sage: f = ntl.ZZ_pX([0,1],c)
|
|
911
|
+
sage: f.is_x()
|
|
912
|
+
True
|
|
913
|
+
sage: f = ntl.ZZ_pX([1],c)
|
|
914
|
+
sage: f.is_x()
|
|
915
|
+
False
|
|
916
|
+
"""
|
|
917
|
+
return bool(ZZ_pX_IsX(self.x))
|
|
918
|
+
|
|
919
|
+
def convert_to_modulus(self, ntl_ZZ_pContext_class c):
|
|
920
|
+
"""
|
|
921
|
+
Return a new ntl_ZZ_pX which is the same as self, but considered modulo a different p.
|
|
922
|
+
|
|
923
|
+
In order for this to make mathematical sense, c.p should divide self.c.p
|
|
924
|
+
(in which case ``self`` is reduced modulo c.p) or self.c.p should divide c.p
|
|
925
|
+
(in which case ``self`` is lifted to something modulo c.p congruent to ``self`` modulo self.c.p)
|
|
926
|
+
|
|
927
|
+
EXAMPLES::
|
|
928
|
+
|
|
929
|
+
sage: a = ntl.ZZ_pX([412,181,991],5^4)
|
|
930
|
+
sage: a
|
|
931
|
+
[412 181 366]
|
|
932
|
+
sage: b = ntl.ZZ_pX([198,333,91],5^4)
|
|
933
|
+
sage: ap = a.convert_to_modulus(ntl.ZZ_pContext(5^2))
|
|
934
|
+
sage: bp = b.convert_to_modulus(ntl.ZZ_pContext(5^2))
|
|
935
|
+
sage: ap
|
|
936
|
+
[12 6 16]
|
|
937
|
+
sage: bp
|
|
938
|
+
[23 8 16]
|
|
939
|
+
sage: ap*bp
|
|
940
|
+
[1 9 8 24 6]
|
|
941
|
+
sage: (a*b).convert_to_modulus(ntl.ZZ_pContext(5^2))
|
|
942
|
+
[1 9 8 24 6]
|
|
943
|
+
"""
|
|
944
|
+
c.restore_c()
|
|
945
|
+
cdef ntl_ZZ_pX ans = ntl_ZZ_pX.__new__(ntl_ZZ_pX)
|
|
946
|
+
ZZ_pX_conv_modulus(ans.x, self.x, c.x)
|
|
947
|
+
ans.c = c
|
|
948
|
+
return ans
|
|
949
|
+
|
|
950
|
+
def derivative(self):
|
|
951
|
+
"""
|
|
952
|
+
Return the derivative of this polynomial.
|
|
953
|
+
|
|
954
|
+
EXAMPLES::
|
|
955
|
+
|
|
956
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
957
|
+
sage: f = ntl.ZZ_pX([1,7,0,13],c)
|
|
958
|
+
sage: f.derivative()
|
|
959
|
+
[7 0 19]
|
|
960
|
+
"""
|
|
961
|
+
cdef ntl_ZZ_pX r = self._new() # restores context
|
|
962
|
+
sig_on()
|
|
963
|
+
ZZ_pX_diff(r.x, self.x)
|
|
964
|
+
sig_off()
|
|
965
|
+
return r
|
|
966
|
+
|
|
967
|
+
def factor(self, verbose=False):
|
|
968
|
+
"""
|
|
969
|
+
Return the factorization of ``self``. Assumes ``self`` is
|
|
970
|
+
monic.
|
|
971
|
+
|
|
972
|
+
NOTE: The roots are returned in a random order.
|
|
973
|
+
|
|
974
|
+
EXAMPLES:
|
|
975
|
+
|
|
976
|
+
These computations use pseudo-random numbers, so we set the
|
|
977
|
+
seed for reproducible testing. ::
|
|
978
|
+
|
|
979
|
+
sage: set_random_seed(12)
|
|
980
|
+
sage: ntl.ZZ_pX([-1,0,0,0,0,1],5).factor()
|
|
981
|
+
[([4 1], 5)]
|
|
982
|
+
sage: ls = ntl.ZZ_pX([-1,0,0,0,1],5).factor()
|
|
983
|
+
sage: ls
|
|
984
|
+
[([4 1], 1), ([2 1], 1), ([1 1], 1), ([3 1], 1)]
|
|
985
|
+
sage: prod( [ x[0] for x in ls ] )
|
|
986
|
+
[4 0 0 0 1]
|
|
987
|
+
sage: ntl.ZZ_pX([3,7,0,1], 31).factor()
|
|
988
|
+
[([3 7 0 1], 1)]
|
|
989
|
+
sage: ntl.ZZ_pX([3,7,1,8], 28).factor()
|
|
990
|
+
Traceback (most recent call last):
|
|
991
|
+
...
|
|
992
|
+
ValueError: self must be monic.
|
|
993
|
+
"""
|
|
994
|
+
current_randstate().set_seed_ntl(False)
|
|
995
|
+
|
|
996
|
+
self.c.restore_c()
|
|
997
|
+
cdef ZZ_pX_c** v
|
|
998
|
+
cdef ntl_ZZ_pX r
|
|
999
|
+
cdef long* e
|
|
1000
|
+
cdef long i, n
|
|
1001
|
+
if not self.is_monic():
|
|
1002
|
+
raise ValueError("self must be monic.")
|
|
1003
|
+
sig_on()
|
|
1004
|
+
ZZ_pX_factor(&v, &e, &n, &self.x, verbose)
|
|
1005
|
+
sig_off()
|
|
1006
|
+
F = []
|
|
1007
|
+
for i from 0 <= i < n:
|
|
1008
|
+
r = self._new()
|
|
1009
|
+
r.x = v[i][0]
|
|
1010
|
+
F.append((r, e[i]))
|
|
1011
|
+
#F.append((make_ZZ_pX(v[i], self.c), e[i]))
|
|
1012
|
+
for i from 0 <= i < n:
|
|
1013
|
+
del v[i]
|
|
1014
|
+
sig_free(v)
|
|
1015
|
+
sig_free(e)
|
|
1016
|
+
return F
|
|
1017
|
+
|
|
1018
|
+
def linear_roots(self):
|
|
1019
|
+
"""
|
|
1020
|
+
Assumes that input is monic, and has deg(f) roots.
|
|
1021
|
+
Returns the list of roots.
|
|
1022
|
+
|
|
1023
|
+
NOTE: This function will go into an infinite loop if you
|
|
1024
|
+
give it a polynomial without deg(f) linear factors. Note
|
|
1025
|
+
also that the result is not deterministic, i.e. the
|
|
1026
|
+
order of the roots returned is random.
|
|
1027
|
+
|
|
1028
|
+
EXAMPLES::
|
|
1029
|
+
|
|
1030
|
+
sage: ntl.ZZ_pX([-1,0,0,0,0,1],5).linear_roots()
|
|
1031
|
+
[1, 1, 1, 1, 1]
|
|
1032
|
+
sage: roots = ntl.ZZ_pX([-1,0,0,0,1],5).linear_roots()
|
|
1033
|
+
sage: [ ntl.ZZ_p(i,5) in roots for i in [1..4] ]
|
|
1034
|
+
[True, True, True, True]
|
|
1035
|
+
sage: ntl.ZZ_pX([3,7,1,8], 28).linear_roots()
|
|
1036
|
+
Traceback (most recent call last):
|
|
1037
|
+
...
|
|
1038
|
+
ValueError: self must be monic.
|
|
1039
|
+
"""
|
|
1040
|
+
current_randstate().set_seed_ntl(False)
|
|
1041
|
+
|
|
1042
|
+
self.c.restore_c()
|
|
1043
|
+
cdef ZZ_p_c** v
|
|
1044
|
+
cdef ntl_ZZ_p r
|
|
1045
|
+
cdef long i, n
|
|
1046
|
+
if not self.is_monic():
|
|
1047
|
+
raise ValueError("self must be monic.")
|
|
1048
|
+
sig_on()
|
|
1049
|
+
ZZ_pX_linear_roots(&v, &n, &self.x)
|
|
1050
|
+
sig_off()
|
|
1051
|
+
F = []
|
|
1052
|
+
for i from 0 <= i < n:
|
|
1053
|
+
r = ntl_ZZ_p.__new__(ntl_ZZ_p)
|
|
1054
|
+
r.c = self.c
|
|
1055
|
+
r.x = v[i][0]
|
|
1056
|
+
F.append(r)
|
|
1057
|
+
#F.append(make_ZZ_p(v[i], self.c))
|
|
1058
|
+
for i from 0 <= i < n:
|
|
1059
|
+
del v[i]
|
|
1060
|
+
sig_free(v)
|
|
1061
|
+
return F
|
|
1062
|
+
|
|
1063
|
+
def reverse(self, hi=None):
|
|
1064
|
+
"""
|
|
1065
|
+
Return the polynomial obtained by reversing the coefficients
|
|
1066
|
+
of this polynomial. If hi is set then this function behaves
|
|
1067
|
+
as if this polynomial has degree hi.
|
|
1068
|
+
|
|
1069
|
+
EXAMPLES::
|
|
1070
|
+
|
|
1071
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1072
|
+
sage: f = ntl.ZZ_pX([1,2,3,4,5],c)
|
|
1073
|
+
sage: f.reverse()
|
|
1074
|
+
[5 4 3 2 1]
|
|
1075
|
+
sage: f.reverse(hi=10)
|
|
1076
|
+
[0 0 0 0 0 0 5 4 3 2 1]
|
|
1077
|
+
sage: f.reverse(hi=2)
|
|
1078
|
+
[3 2 1]
|
|
1079
|
+
sage: f.reverse(hi=-2)
|
|
1080
|
+
[]
|
|
1081
|
+
"""
|
|
1082
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1083
|
+
if hi is None:
|
|
1084
|
+
ZZ_pX_reverse(r.x, self.x)
|
|
1085
|
+
else:
|
|
1086
|
+
ZZ_pX_reverse_hi(r.x, self.x, int(hi))
|
|
1087
|
+
return r
|
|
1088
|
+
|
|
1089
|
+
def truncate(self, long m):
|
|
1090
|
+
"""
|
|
1091
|
+
Return the truncation of this polynomial obtained by
|
|
1092
|
+
removing all terms of degree >= m.
|
|
1093
|
+
|
|
1094
|
+
EXAMPLES::
|
|
1095
|
+
|
|
1096
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1097
|
+
sage: f = ntl.ZZ_pX([1,2,3,4,5],c)
|
|
1098
|
+
sage: f.truncate(3)
|
|
1099
|
+
[1 2 3]
|
|
1100
|
+
sage: f.truncate(8)
|
|
1101
|
+
[1 2 3 4 5]
|
|
1102
|
+
sage: f.truncate(1)
|
|
1103
|
+
[1]
|
|
1104
|
+
sage: f.truncate(0)
|
|
1105
|
+
[]
|
|
1106
|
+
sage: f.truncate(-1)
|
|
1107
|
+
[]
|
|
1108
|
+
sage: f.truncate(-5)
|
|
1109
|
+
[]
|
|
1110
|
+
"""
|
|
1111
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1112
|
+
if m <= 0:
|
|
1113
|
+
return r
|
|
1114
|
+
sig_on()
|
|
1115
|
+
ZZ_pX_trunc(r.x, self.x, m)
|
|
1116
|
+
sig_off()
|
|
1117
|
+
return r
|
|
1118
|
+
|
|
1119
|
+
def multiply_and_truncate(self, ntl_ZZ_pX other, long m):
|
|
1120
|
+
"""
|
|
1121
|
+
Return self*other but with terms of degree >= m removed.
|
|
1122
|
+
|
|
1123
|
+
EXAMPLES::
|
|
1124
|
+
|
|
1125
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1126
|
+
sage: f = ntl.ZZ_pX([1,2,3,4,5],c)
|
|
1127
|
+
sage: g = ntl.ZZ_pX([10],c)
|
|
1128
|
+
sage: f.multiply_and_truncate(g, 2)
|
|
1129
|
+
[10]
|
|
1130
|
+
sage: g.multiply_and_truncate(f, 2)
|
|
1131
|
+
[10]
|
|
1132
|
+
"""
|
|
1133
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1134
|
+
if m <= 0:
|
|
1135
|
+
return r
|
|
1136
|
+
sig_on()
|
|
1137
|
+
ZZ_pX_MulTrunc(r.x, self.x, other.x, m)
|
|
1138
|
+
sig_off()
|
|
1139
|
+
return r
|
|
1140
|
+
|
|
1141
|
+
def square_and_truncate(self, long m):
|
|
1142
|
+
"""
|
|
1143
|
+
Return self*self but with terms of degree >= m removed.
|
|
1144
|
+
|
|
1145
|
+
EXAMPLES::
|
|
1146
|
+
|
|
1147
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1148
|
+
sage: f = ntl.ZZ_pX([1,2,3,4,5],c)
|
|
1149
|
+
sage: f.square_and_truncate(4)
|
|
1150
|
+
[1 4 10]
|
|
1151
|
+
sage: (f*f).truncate(4)
|
|
1152
|
+
[1 4 10]
|
|
1153
|
+
"""
|
|
1154
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1155
|
+
if m <= 0:
|
|
1156
|
+
return r
|
|
1157
|
+
sig_on()
|
|
1158
|
+
ZZ_pX_SqrTrunc(r.x, self.x, m)
|
|
1159
|
+
sig_off()
|
|
1160
|
+
return r
|
|
1161
|
+
|
|
1162
|
+
def invert_and_truncate(self, long m):
|
|
1163
|
+
"""
|
|
1164
|
+
Compute and return the inverse of ``self`` modulo `x^m`.
|
|
1165
|
+
|
|
1166
|
+
The constant term of ``self`` must be a unit.
|
|
1167
|
+
|
|
1168
|
+
EXAMPLES::
|
|
1169
|
+
|
|
1170
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1171
|
+
sage: f = ntl.ZZ_pX([1,2,3,4,5,6,7],c)
|
|
1172
|
+
sage: f.invert_and_truncate(20)
|
|
1173
|
+
[1 18 1 0 0 0 0 8 17 2 13 0 0 0 4 0 17 10 9]
|
|
1174
|
+
sage: g = f.invert_and_truncate(20)
|
|
1175
|
+
sage: g * f
|
|
1176
|
+
[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]
|
|
1177
|
+
"""
|
|
1178
|
+
if m < 0:
|
|
1179
|
+
raise ArithmeticError("m (=%s) must be positive" % m)
|
|
1180
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1181
|
+
sig_on()
|
|
1182
|
+
ZZ_pX_InvTrunc(r.x, self.x, m)
|
|
1183
|
+
sig_off()
|
|
1184
|
+
return r
|
|
1185
|
+
|
|
1186
|
+
def invmod(self, ntl_ZZ_pX modulus):
|
|
1187
|
+
"""
|
|
1188
|
+
Return the inverse of ``self`` modulo the modulus using NTL's InvMod.
|
|
1189
|
+
"""
|
|
1190
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1191
|
+
sig_on()
|
|
1192
|
+
ZZ_pX_InvMod(r.x, self.x, modulus.x)
|
|
1193
|
+
sig_off()
|
|
1194
|
+
return r
|
|
1195
|
+
|
|
1196
|
+
def invmod_newton(self, ntl_ZZ_pX modulus):
|
|
1197
|
+
"""
|
|
1198
|
+
Return the inverse of ``self`` modulo the modulus using Newton lifting.
|
|
1199
|
+
Only works if modulo a power of a prime, and if modulus is either
|
|
1200
|
+
unramified or Eisenstein.
|
|
1201
|
+
"""
|
|
1202
|
+
cdef Integer pn = Integer(self.c.p)
|
|
1203
|
+
cdef ntl_ZZ_pX ans = self._new()
|
|
1204
|
+
F = pn.factor()
|
|
1205
|
+
if len(F) > 1:
|
|
1206
|
+
raise ValueError("must be modulo a prime power")
|
|
1207
|
+
p = F[0][0]
|
|
1208
|
+
cdef ntl_ZZ pZZ = <ntl_ZZ>ntl_ZZ(p)
|
|
1209
|
+
cdef ZZ_pX_Modulus_c mod
|
|
1210
|
+
ZZ_pX_Modulus_build(mod, modulus.x)
|
|
1211
|
+
cdef ntl_ZZ_pX mod_prime
|
|
1212
|
+
cdef ntl_ZZ_pContext_class ctx
|
|
1213
|
+
cdef long mini = 0, minval = 0
|
|
1214
|
+
if Integer(modulus[0].lift()).valuation(p) == 1:
|
|
1215
|
+
eisenstein = True
|
|
1216
|
+
for c in modulus.list()[1:-1]:
|
|
1217
|
+
if not p.divides(Integer(c.lift())):
|
|
1218
|
+
eisenstein = False
|
|
1219
|
+
break
|
|
1220
|
+
if eisenstein:
|
|
1221
|
+
if p.divides(Integer(self[0])):
|
|
1222
|
+
raise ZeroDivisionError("cannot invert element")
|
|
1223
|
+
ZZ_pX_InvMod_newton_ram(ans.x, self.x, mod, self.c.x)
|
|
1224
|
+
else:
|
|
1225
|
+
raise ValueError("not eisenstein or unramified")
|
|
1226
|
+
else:
|
|
1227
|
+
ctx = <ntl_ZZ_pContext_class>ntl_ZZ_pContext(p)
|
|
1228
|
+
mod_prime = ntl_ZZ_pX.__new__(ntl_ZZ_pX)
|
|
1229
|
+
ZZ_pX_conv_modulus(mod_prime.x, modulus.x, ctx.x)
|
|
1230
|
+
mod_prime.c = ctx
|
|
1231
|
+
F = mod_prime.factor()
|
|
1232
|
+
if len(F) == 1 and F[0][1] == 1:
|
|
1233
|
+
ZZ_pX_min_val_coeff(minval, mini, self.x, pZZ.x)
|
|
1234
|
+
if minval > 0:
|
|
1235
|
+
raise ZeroDivisionError("cannot invert element")
|
|
1236
|
+
ZZ_pX_InvMod_newton_unram(ans.x, self.x, mod, self.c.x, ctx.x)
|
|
1237
|
+
else:
|
|
1238
|
+
raise ValueError("not eisenstein or unramified")
|
|
1239
|
+
return ans
|
|
1240
|
+
|
|
1241
|
+
def multiply_mod(self, ntl_ZZ_pX other, ntl_ZZ_pX modulus):
|
|
1242
|
+
"""
|
|
1243
|
+
Return ``self*other % modulus``. The modulus must be monic with
|
|
1244
|
+
``deg(modulus) > 0``, and ``self`` and ``other`` must have smaller degree.
|
|
1245
|
+
|
|
1246
|
+
EXAMPLES::
|
|
1247
|
+
|
|
1248
|
+
sage: c = ntl.ZZ_pContext(ntl.ZZ(20))
|
|
1249
|
+
sage: modulus = ntl.ZZ_pX([1,2,0,1],c) # must be monic
|
|
1250
|
+
sage: g = ntl.ZZ_pX([-1,0,1],c)
|
|
1251
|
+
sage: h = ntl.ZZ_pX([3,7,13],c)
|
|
1252
|
+
sage: h.multiply_mod(g, modulus)
|
|
1253
|
+
[10 6 4]
|
|
1254
|
+
"""
|
|
1255
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1256
|
+
sig_on()
|
|
1257
|
+
ZZ_pX_MulMod(r.x, self.x, other.x, modulus.x)
|
|
1258
|
+
sig_off()
|
|
1259
|
+
return r
|
|
1260
|
+
|
|
1261
|
+
def trace_mod(self, ntl_ZZ_pX modulus):
|
|
1262
|
+
"""
|
|
1263
|
+
Return the trace of this polynomial modulus the modulus.
|
|
1264
|
+
The modulus must be monic, and of positive degree bigger
|
|
1265
|
+
than the degree of ``self``.
|
|
1266
|
+
|
|
1267
|
+
EXAMPLES::
|
|
1268
|
+
|
|
1269
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1270
|
+
sage: f = ntl.ZZ_pX([1,2,0,3],c)
|
|
1271
|
+
sage: mod = ntl.ZZ_pX([5,3,-1,1,1],c)
|
|
1272
|
+
sage: f.trace_mod(mod)
|
|
1273
|
+
3
|
|
1274
|
+
"""
|
|
1275
|
+
self.c.restore_c()
|
|
1276
|
+
cdef ntl_ZZ_p r = ntl_ZZ_p.__new__(ntl_ZZ_p)
|
|
1277
|
+
r.c = self.c
|
|
1278
|
+
sig_on()
|
|
1279
|
+
ZZ_pX_TraceMod(r.x, self.x, modulus.x)
|
|
1280
|
+
sig_off()
|
|
1281
|
+
return r
|
|
1282
|
+
|
|
1283
|
+
def trace_list(self):
|
|
1284
|
+
"""
|
|
1285
|
+
Return the list of traces of the powers `x^i` of the
|
|
1286
|
+
monomial x modulo this polynomial for i = 0, ..., deg(f)-1.
|
|
1287
|
+
|
|
1288
|
+
This polynomial must be monic.
|
|
1289
|
+
|
|
1290
|
+
EXAMPLES::
|
|
1291
|
+
|
|
1292
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1293
|
+
sage: f = ntl.ZZ_pX([1,2,0,3,0,1],c)
|
|
1294
|
+
sage: f.trace_list()
|
|
1295
|
+
[5, 0, 14, 0, 10]
|
|
1296
|
+
|
|
1297
|
+
The input polynomial must be monic or a :exc:`ValueError` is raised::
|
|
1298
|
+
|
|
1299
|
+
sage: c = ntl.ZZ_pContext(20)
|
|
1300
|
+
sage: f = ntl.ZZ_pX([1,2,0,3,0,2],c)
|
|
1301
|
+
sage: f.trace_list()
|
|
1302
|
+
Traceback (most recent call last):
|
|
1303
|
+
...
|
|
1304
|
+
ValueError: polynomial must be monic.
|
|
1305
|
+
"""
|
|
1306
|
+
# This function should be redone to use TraceVec, which requires improving the wrapper for vec_ZZ_p
|
|
1307
|
+
self.c.restore_c()
|
|
1308
|
+
if not self.is_monic():
|
|
1309
|
+
raise ValueError("polynomial must be monic.")
|
|
1310
|
+
sig_on()
|
|
1311
|
+
cdef char* t
|
|
1312
|
+
t = ZZ_pX_trace_list(&self.x)
|
|
1313
|
+
r = eval(char_to_str(t).replace(' ', ','))
|
|
1314
|
+
string_delete(t)
|
|
1315
|
+
return r
|
|
1316
|
+
|
|
1317
|
+
def resultant(self, ntl_ZZ_pX other):
|
|
1318
|
+
"""
|
|
1319
|
+
Return the resultant of ``self`` and ``other``.
|
|
1320
|
+
|
|
1321
|
+
EXAMPLES::
|
|
1322
|
+
|
|
1323
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
1324
|
+
sage: f = ntl.ZZ_pX([17,0,1,1],c)
|
|
1325
|
+
sage: g = ntl.ZZ_pX([34,-17,18,2],c)
|
|
1326
|
+
sage: f.resultant(g)
|
|
1327
|
+
0
|
|
1328
|
+
"""
|
|
1329
|
+
self.c.restore_c()
|
|
1330
|
+
cdef ntl_ZZ_p r = ntl_ZZ_p.__new__(ntl_ZZ_p)
|
|
1331
|
+
r.c = self.c
|
|
1332
|
+
sig_on()
|
|
1333
|
+
ZZ_pX_resultant(r.x, self.x, other.x)
|
|
1334
|
+
sig_off()
|
|
1335
|
+
return r
|
|
1336
|
+
|
|
1337
|
+
def norm_mod(self, ntl_ZZ_pX modulus):
|
|
1338
|
+
"""
|
|
1339
|
+
Return the norm of this polynomial modulo the modulus. The
|
|
1340
|
+
modulus must be monic, and of positive degree strictly greater
|
|
1341
|
+
than the degree of ``self``.
|
|
1342
|
+
|
|
1343
|
+
EXAMPLES::
|
|
1344
|
+
|
|
1345
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
1346
|
+
sage: f = ntl.ZZ_pX([1,2,0,3],c)
|
|
1347
|
+
sage: mod = ntl.ZZ_pX([-5,2,0,0,1],c)
|
|
1348
|
+
sage: f.norm_mod(mod)
|
|
1349
|
+
11
|
|
1350
|
+
|
|
1351
|
+
The norm is the constant term of the characteristic polynomial::
|
|
1352
|
+
|
|
1353
|
+
sage: f.charpoly_mod(mod)
|
|
1354
|
+
[11 1 8 14 1]
|
|
1355
|
+
"""
|
|
1356
|
+
self.c.restore_c()
|
|
1357
|
+
cdef ntl_ZZ_p r = ntl_ZZ_p.__new__(ntl_ZZ_p)
|
|
1358
|
+
r.c = self.c
|
|
1359
|
+
sig_on()
|
|
1360
|
+
ZZ_pX_NormMod(r.x, self.x, modulus.x)
|
|
1361
|
+
sig_off()
|
|
1362
|
+
return r
|
|
1363
|
+
|
|
1364
|
+
def discriminant(self):
|
|
1365
|
+
r"""
|
|
1366
|
+
Return the discriminant of a=self, which is by definition
|
|
1367
|
+
$$
|
|
1368
|
+
(-1)^{m(m-1)/2} {\mbox{\tt resultant}}(a, a')/lc(a),
|
|
1369
|
+
$$
|
|
1370
|
+
where m = deg(a), and lc(a) is the leading coefficient of a.
|
|
1371
|
+
|
|
1372
|
+
EXAMPLES::
|
|
1373
|
+
|
|
1374
|
+
sage: c = ntl.ZZ_pContext(ntl.ZZ(17))
|
|
1375
|
+
sage: f = ntl.ZZ_pX([1,2,0,3],c)
|
|
1376
|
+
sage: f.discriminant()
|
|
1377
|
+
1
|
|
1378
|
+
"""
|
|
1379
|
+
self.c.restore_c()
|
|
1380
|
+
cdef long m
|
|
1381
|
+
|
|
1382
|
+
c = ~self.leading_coefficient()
|
|
1383
|
+
m = self.degree()
|
|
1384
|
+
if (m*(m-1) // 2) % 2:
|
|
1385
|
+
c = -c
|
|
1386
|
+
return c*self.resultant(self.derivative())
|
|
1387
|
+
|
|
1388
|
+
def charpoly_mod(self, ntl_ZZ_pX modulus):
|
|
1389
|
+
"""
|
|
1390
|
+
Return the characteristic polynomial of this polynomial modulo
|
|
1391
|
+
the modulus. The modulus must be monic of degree bigger than
|
|
1392
|
+
``self``.
|
|
1393
|
+
|
|
1394
|
+
EXAMPLES::
|
|
1395
|
+
|
|
1396
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
1397
|
+
sage: f = ntl.ZZ_pX([1,2,0,3],c)
|
|
1398
|
+
sage: mod = ntl.ZZ_pX([-5,2,0,0,1],c)
|
|
1399
|
+
sage: f.charpoly_mod(mod)
|
|
1400
|
+
[11 1 8 14 1]
|
|
1401
|
+
"""
|
|
1402
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1403
|
+
sig_on()
|
|
1404
|
+
ZZ_pX_CharPolyMod(r.x, self.x, modulus.x)
|
|
1405
|
+
sig_off()
|
|
1406
|
+
return r
|
|
1407
|
+
|
|
1408
|
+
def minpoly_mod(self, ntl_ZZ_pX modulus):
|
|
1409
|
+
"""
|
|
1410
|
+
Return the minimal polynomial of this polynomial modulo the
|
|
1411
|
+
modulus. The modulus must be monic of degree bigger than
|
|
1412
|
+
``self``.
|
|
1413
|
+
|
|
1414
|
+
EXAMPLES::
|
|
1415
|
+
|
|
1416
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
1417
|
+
sage: f = ntl.ZZ_pX([0,0,1],c)
|
|
1418
|
+
sage: g = f*f
|
|
1419
|
+
sage: f.charpoly_mod(g)
|
|
1420
|
+
[0 0 0 0 1]
|
|
1421
|
+
|
|
1422
|
+
However, since `f^2 = 0` modulo `g`, its minimal polynomial
|
|
1423
|
+
is of degree `2`::
|
|
1424
|
+
|
|
1425
|
+
sage: f.minpoly_mod(g)
|
|
1426
|
+
[0 0 1]
|
|
1427
|
+
"""
|
|
1428
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1429
|
+
sig_on()
|
|
1430
|
+
ZZ_pX_MinPolyMod(r.x, self.x, modulus.x)
|
|
1431
|
+
sig_off()
|
|
1432
|
+
return r
|
|
1433
|
+
|
|
1434
|
+
def clear(self):
|
|
1435
|
+
"""
|
|
1436
|
+
Reset this polynomial to 0. Changes this polynomial in place.
|
|
1437
|
+
|
|
1438
|
+
EXAMPLES::
|
|
1439
|
+
|
|
1440
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
1441
|
+
sage: f = ntl.ZZ_pX([1,2,3],c)
|
|
1442
|
+
sage: f
|
|
1443
|
+
[1 2 3]
|
|
1444
|
+
sage: f.clear()
|
|
1445
|
+
sage: f
|
|
1446
|
+
[]
|
|
1447
|
+
"""
|
|
1448
|
+
self.c.restore_c()
|
|
1449
|
+
ZZ_pX_clear(self.x)
|
|
1450
|
+
|
|
1451
|
+
def preallocate_space(self, long n):
|
|
1452
|
+
"""
|
|
1453
|
+
Pre-allocate spaces for n coefficients. The polynomial that f
|
|
1454
|
+
represents is unchanged. This is useful if you know you'll be
|
|
1455
|
+
setting coefficients up to n, so memory isn't re-allocated as
|
|
1456
|
+
the polynomial grows. (You might save a millisecond with this
|
|
1457
|
+
function.)
|
|
1458
|
+
|
|
1459
|
+
EXAMPLES::
|
|
1460
|
+
|
|
1461
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
1462
|
+
sage: f = ntl.ZZ_pX([1,2,3],c)
|
|
1463
|
+
sage: f.preallocate_space(20)
|
|
1464
|
+
sage: f
|
|
1465
|
+
[1 2 3]
|
|
1466
|
+
sage: f[10]=5 # no new memory is allocated
|
|
1467
|
+
sage: f
|
|
1468
|
+
[1 2 3 0 0 0 0 0 0 0 5]
|
|
1469
|
+
"""
|
|
1470
|
+
self.c.restore_c()
|
|
1471
|
+
sig_on()
|
|
1472
|
+
self.x.SetMaxLength(n)
|
|
1473
|
+
#ZZ_pX_preallocate_space(&self.x, n)
|
|
1474
|
+
sig_off()
|
|
1475
|
+
|
|
1476
|
+
def compose_mod(self, ntl_ZZ_pX other, ntl_ZZ_pX modulus):
|
|
1477
|
+
r"""
|
|
1478
|
+
Compute `f(g) \bmod h`.
|
|
1479
|
+
|
|
1480
|
+
To be precise about the order fo compostion, given ``self``, ``other``
|
|
1481
|
+
and ``modulus`` as `f(x)`, `g(x)` and `h(x)` compute `f(g(x)) \bmod h(x)`.
|
|
1482
|
+
|
|
1483
|
+
INPUT:
|
|
1484
|
+
|
|
1485
|
+
- ``other`` -- a polynomial `g(x)`
|
|
1486
|
+
- ``modulus`` -- a polynomial `h(x)`
|
|
1487
|
+
|
|
1488
|
+
EXAMPLES::
|
|
1489
|
+
|
|
1490
|
+
sage: c = ntl.ZZ_pContext(17)
|
|
1491
|
+
sage: f = ntl.ZZ_pX([1,2,3],c)
|
|
1492
|
+
sage: g = ntl.ZZ_pX([3,2,1],c)
|
|
1493
|
+
sage: h = ntl.ZZ_pX([1,0,1],c)
|
|
1494
|
+
sage: f.compose_mod(g, h)
|
|
1495
|
+
[5 11]
|
|
1496
|
+
|
|
1497
|
+
AUTHORS:
|
|
1498
|
+
|
|
1499
|
+
- Giacomo Pope (2024-08) initial implementation
|
|
1500
|
+
"""
|
|
1501
|
+
cdef ntl_ZZ_pX r = self._new()
|
|
1502
|
+
cdef ZZ_pX_Modulus_c mod
|
|
1503
|
+
|
|
1504
|
+
sig_on()
|
|
1505
|
+
# NTL requires that g is reduced
|
|
1506
|
+
other = other % modulus
|
|
1507
|
+
|
|
1508
|
+
# Build the modulus type
|
|
1509
|
+
ZZ_pX_Modulus_build(mod, modulus.x)
|
|
1510
|
+
|
|
1511
|
+
# Compute f(g) % h
|
|
1512
|
+
ZZ_pX_CompMod(r.x, self.x, other.x, mod)
|
|
1513
|
+
sig_off()
|
|
1514
|
+
return r
|
|
1515
|
+
|
|
1516
|
+
cdef class ntl_ZZ_pX_Modulus():
|
|
1517
|
+
"""
|
|
1518
|
+
Thin holder for ZZ_pX_Moduli.
|
|
1519
|
+
"""
|
|
1520
|
+
def __cinit__(self, ntl_ZZ_pX poly):
|
|
1521
|
+
ZZ_pX_Modulus_build(self.x, poly.x)
|
|
1522
|
+
self.poly = poly
|
|
1523
|
+
|
|
1524
|
+
def __repr__(self) -> str:
|
|
1525
|
+
return "NTL ZZ_pXModulus %s (mod %s)" % (self.poly, self.poly.c.p)
|
|
1526
|
+
|
|
1527
|
+
def degree(self):
|
|
1528
|
+
cdef Integer ans = Integer.__new__(Integer)
|
|
1529
|
+
mpz_set_ui(ans.value, ZZ_pX_Modulus_deg(self.x))
|
|
1530
|
+
return ans
|
|
1531
|
+
|
|
1532
|
+
## TODO: NTL's ZZ_pX has minpolys of linear recurrence sequences!!!
|