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