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