Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/libs/ntl/ntl_ZZX.pyx
4108 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 "decl.pxi"
19
include 'misc.pxi'
20
21
from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ
22
from sage.libs.ntl.ntl_ZZ import unpickle_class_value
23
24
from sage.rings.integer import Integer
25
from sage.rings.integer_ring import IntegerRing
26
from sage.rings.integer cimport Integer
27
from sage.rings.integer_ring cimport IntegerRing_class
28
29
ZZ = IntegerRing()
30
31
cdef inline ntl_ZZ make_ZZ(ZZ_c* x):
32
""" These make_XXXX functions are deprecated and should be phased out."""
33
cdef ntl_ZZ y
34
y = ntl_ZZ()
35
y.x = x[0]
36
ZZ_delete(x)
37
return y
38
39
# You must do sig_on() before calling this function
40
cdef inline ntl_ZZ make_ZZ_sig_off(ZZ_c* x):
41
cdef ntl_ZZ y = make_ZZ(x)
42
sig_off()
43
return y
44
45
cdef inline ntl_ZZX make_ZZX(ZZX_c* x):
46
""" These make_XXXX functions are deprecated and should be phased out."""
47
cdef ntl_ZZX y
48
y = ntl_ZZX()
49
y.x = x[0]
50
ZZX_delete(x)
51
return y
52
53
# You must do sig_on() before calling this function
54
cdef inline ntl_ZZX make_ZZX_sig_off(ZZX_c* x):
55
cdef ntl_ZZX y = make_ZZX(x)
56
sig_off()
57
return y
58
59
from sage.structure.proof.proof import get_flag
60
cdef proof_flag(t):
61
return get_flag(t, "polynomial")
62
63
##############################################################################
64
#
65
# ZZX: polynomials over the integers
66
#
67
##############################################################################
68
69
70
cdef class ntl_ZZX:
71
r"""
72
The class \class{ZZX} implements polynomials in $\Z[X]$, i.e.,
73
univariate polynomials with integer coefficients.
74
75
Polynomial multiplication is very fast, and is implemented using
76
one of 4 different algorithms:
77
\begin{enumerate}
78
\item\hspace{1em} Classical
79
\item\hspace{1em} Karatsuba
80
\item\hspace{1em} Schoenhage and Strassen --- performs an FFT by working
81
modulo a "Fermat number" of appropriate size...
82
good for polynomials with huge coefficients
83
and moderate degree
84
\item\hspace{1em} CRT/FFT --- performs an FFT by working modulo several
85
small primes. This is good for polynomials with moderate
86
coefficients and huge degree.
87
\end{enumerate}
88
89
The choice of algorithm is somewhat heuristic, and may not always be
90
perfect.
91
92
Many thanks to Juergen Gerhard {\tt
93
<[email protected]>} for pointing out the deficiency
94
in the NTL-1.0 ZZX arithmetic, and for contributing the
95
Schoenhage/Strassen code.
96
97
Extensive use is made of modular algorithms to enhance performance
98
(e.g., the GCD algorithm and many others).
99
"""
100
101
# See ntl_ZZX.pxd for definition of data members
102
def __init__(self, v=None):
103
"""
104
EXAMPLES:
105
sage: f = ntl.ZZX([1,2,5,-9])
106
sage: f
107
[1 2 5 -9]
108
sage: g = ntl.ZZX([0,0,0]); g
109
[]
110
sage: g[10]=5
111
sage: g
112
[0 0 0 0 0 0 0 0 0 0 5]
113
sage: g[10]
114
5
115
"""
116
cdef ntl_ZZ cc
117
cdef Py_ssize_t i
118
119
if v is None:
120
return
121
elif PY_TYPE_CHECK(v, list) or PY_TYPE_CHECK(v, tuple):
122
for i from 0 <= i < len(v):
123
x = v[i]
124
if not PY_TYPE_CHECK(x, ntl_ZZ):
125
cc = ntl_ZZ(x)
126
else:
127
cc = x
128
ZZX_SetCoeff(self.x, i, cc.x)
129
else:
130
v = str(v)
131
ZZX_from_str(&self.x, v)
132
133
def __reduce__(self):
134
"""
135
sage: from sage.libs.ntl.ntl_ZZX import ntl_ZZX
136
sage: f = ntl_ZZX([1,2,0,4])
137
sage: loads(dumps(f)) == f
138
True
139
"""
140
return unpickle_class_value, (ntl_ZZX, self.list())
141
142
def __cinit__(self):
143
ZZX_construct(&self.x)
144
145
def __dealloc__(self):
146
ZZX_destruct(&self.x)
147
148
def __repr__(self):
149
"""
150
Return the string representation of self.
151
152
EXAMPLES:
153
sage: ntl.ZZX([1,3,0,5]).__repr__()
154
'[1 3 0 5]'
155
"""
156
cdef char * val
157
val = ZZX_repr(&self.x)
158
result = str(val)
159
cpp_delete_array(val)
160
return result
161
162
def __copy__(self):
163
"""
164
Return a copy of self.
165
166
EXAMPLES:
167
sage: x = ntl.ZZX([1,32])
168
sage: y = copy(x)
169
sage: y == x
170
True
171
sage: y is x
172
False
173
"""
174
return make_ZZX(ZZX_copy(&self.x))
175
176
def __setitem__(self, long i, a):
177
"""
178
sage: n=ntl.ZZX([1,2,3])
179
sage: n
180
[1 2 3]
181
sage: n[1] = 4
182
sage: n
183
[1 4 3]
184
"""
185
if i < 0:
186
raise IndexError, "index (i=%s) must be >= 0"%i
187
cdef ntl_ZZ cc
188
if PY_TYPE_CHECK(a, ntl_ZZ):
189
cc = a
190
else:
191
cc = ntl_ZZ(a)
192
ZZX_SetCoeff(self.x, i, cc.x)
193
194
cdef void setitem_from_int(ntl_ZZX self, long i, int value):
195
r"""
196
Sets ith coefficient to value.
197
198
AUTHOR: David Harvey (2006-08-05)
199
"""
200
ZZX_setitem_from_int(&self.x, i, value)
201
202
def setitem_from_int_doctest(self, i, value):
203
r"""
204
This method exists solely for automated testing of setitem_from_int().
205
206
sage: x = ntl.ZZX([2, 3, 4])
207
sage: x.setitem_from_int_doctest(5, 42)
208
sage: x
209
[2 3 4 0 0 42]
210
"""
211
self.setitem_from_int(int(i), int(value))
212
213
def __getitem__(self, long i):
214
r"""
215
Retrieves coefficient number i as an NTL ZZ.
216
217
sage: x = ntl.ZZX([129381729371289371237128318293718237, 2, -3, 0, 4])
218
sage: x[0]
219
129381729371289371237128318293718237
220
sage: type(x[0])
221
<type 'sage.libs.ntl.ntl_ZZ.ntl_ZZ'>
222
sage: x[1]
223
2
224
sage: x[2]
225
-3
226
sage: x[3]
227
0
228
sage: x[4]
229
4
230
sage: x[5]
231
0
232
"""
233
cdef ntl_ZZ r = ntl_ZZ()
234
sig_on()
235
r.x = ZZX_coeff(self.x, <long>i)
236
sig_off()
237
return r
238
239
cdef int getitem_as_int(ntl_ZZX self, long i):
240
r"""
241
Returns ith coefficient as C int.
242
Return value is only valid if the result fits into an int.
243
244
AUTHOR: David Harvey (2006-08-05)
245
"""
246
return ZZX_getitem_as_int(&self.x, i)
247
248
def getitem_as_int_doctest(self, i):
249
r"""
250
This method exists solely for automated testing of getitem_as_int().
251
252
sage: x = ntl.ZZX([2, 3, 5, -7, 11])
253
sage: i = x.getitem_as_int_doctest(3)
254
sage: print i
255
-7
256
sage: print type(i)
257
<type 'int'>
258
sage: print x.getitem_as_int_doctest(15)
259
0
260
"""
261
return self.getitem_as_int(i)
262
263
def list(self):
264
r"""
265
Retrieves coefficients as a list of ntl.ZZ Integers.
266
267
EXAMPLES:
268
sage: x = ntl.ZZX([129381729371289371237128318293718237, 2, -3, 0, 4])
269
sage: L = x.list(); L
270
[129381729371289371237128318293718237, 2, -3, 0, 4]
271
sage: type(L[0])
272
<type 'sage.libs.ntl.ntl_ZZ.ntl_ZZ'>
273
sage: x = ntl.ZZX()
274
sage: L = x.list(); L
275
[]
276
"""
277
cdef int i
278
return [self[i] for i from 0 <= i <= ZZX_deg(self.x)]
279
280
def __add__(ntl_ZZX self, ntl_ZZX other):
281
"""
282
EXAMPLES:
283
sage: ntl.ZZX(range(5)) + ntl.ZZX(range(6))
284
[0 2 4 6 8 5]
285
"""
286
cdef ntl_ZZX r = PY_NEW(ntl_ZZX)
287
if not PY_TYPE_CHECK(self, ntl_ZZX):
288
self = ntl_ZZX(self)
289
if not PY_TYPE_CHECK(other, ntl_ZZX):
290
other = ntl_ZZX(other)
291
ZZX_add(r.x, (<ntl_ZZX>self).x, (<ntl_ZZX>other).x)
292
return r
293
294
def __sub__(ntl_ZZX self, ntl_ZZX other):
295
"""
296
EXAMPLES:
297
sage: ntl.ZZX(range(5)) - ntl.ZZX(range(6))
298
[0 0 0 0 0 -5]
299
"""
300
cdef ntl_ZZX r = PY_NEW(ntl_ZZX)
301
if not PY_TYPE_CHECK(self, ntl_ZZX):
302
self = ntl_ZZX(self)
303
if not PY_TYPE_CHECK(other, ntl_ZZX):
304
other = ntl_ZZX(other)
305
ZZX_sub(r.x, (<ntl_ZZX>self).x, (<ntl_ZZX>other).x)
306
return r
307
308
def __mul__(ntl_ZZX self, ntl_ZZX other):
309
"""
310
EXAMPLES:
311
sage: ntl.ZZX(range(5)) * ntl.ZZX(range(6))
312
[0 0 1 4 10 20 30 34 31 20]
313
"""
314
cdef ntl_ZZX r = PY_NEW(ntl_ZZX)
315
if not PY_TYPE_CHECK(self, ntl_ZZX):
316
self = ntl_ZZX(self)
317
if not PY_TYPE_CHECK(other, ntl_ZZX):
318
other = ntl_ZZX(other)
319
sig_on()
320
ZZX_mul(r.x, (<ntl_ZZX>self).x, (<ntl_ZZX>other).x)
321
sig_off()
322
return r
323
324
def __div__(ntl_ZZX self, ntl_ZZX other):
325
"""
326
Compute quotient self / other, if the quotient is a polynomial.
327
Otherwise an Exception is raised.
328
329
EXAMPLES:
330
sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2
331
sage: g = ntl.ZZX([4,5])
332
sage: f/g
333
[4 13 22 15]
334
sage: ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])
335
[4 13 22 15]
336
337
sage: f = ntl.ZZX(range(10)); g = ntl.ZZX([-1,0,1])
338
sage: f/g
339
Traceback (most recent call last):
340
...
341
ArithmeticError: self (=[0 1 2 3 4 5 6 7 8 9]) is not divisible by other (=[-1 0 1])
342
"""
343
sig_on()
344
cdef int divisible
345
cdef ZZX_c* q
346
q = ZZX_div(&self.x, &other.x, &divisible)
347
if not divisible:
348
ZZX_delete(q)
349
sig_off()
350
raise ArithmeticError, "self (=%s) is not divisible by other (=%s)"%(self, other)
351
result = make_ZZX_sig_off(q)
352
return result
353
354
def __mod__(ntl_ZZX self, ntl_ZZX other):
355
"""
356
Given polynomials a, b in ZZ[X], there exist polynomials q, r
357
in QQ[X] such that a = b*q + r, deg(r) < deg(b). This
358
function returns q if q lies in ZZ[X], and otherwise raises an
359
Exception.
360
361
EXAMPLES:
362
sage: f = ntl.ZZX([2,4,6]); g = ntl.ZZX([2])
363
sage: f % g # 0
364
[]
365
366
sage: f = ntl.ZZX(range(10)); g = ntl.ZZX([-1,0,1])
367
sage: f % g
368
[20 25]
369
"""
370
cdef ntl_ZZX r = PY_NEW(ntl_ZZX)
371
if not PY_TYPE_CHECK(self, ntl_ZZX):
372
self = ntl_ZZX(self)
373
if not PY_TYPE_CHECK(other, ntl_ZZX):
374
other = ntl_ZZX(other)
375
sig_on()
376
ZZX_rem(r.x, (<ntl_ZZX>self).x, (<ntl_ZZX>other).x)
377
sig_off()
378
return r
379
sig_on()
380
381
def quo_rem(self, ntl_ZZX other):
382
"""
383
Returns the unique integral q and r such that self = q*other +
384
r, if they exist. Otherwise raises an Exception.
385
386
EXAMPLES:
387
sage: f = ntl.ZZX(range(10)); g = ntl.ZZX([-1,0,1])
388
sage: q, r = f.quo_rem(g)
389
sage: q, r
390
([20 24 18 21 14 16 8 9], [20 25])
391
sage: q*g + r == f
392
True
393
"""
394
cdef ZZX_c *r, *q
395
try:
396
sig_on()
397
ZZX_quo_rem(&self.x, &other.x, &r, &q)
398
return (make_ZZX(q), make_ZZX(r))
399
finally:
400
sig_off()
401
402
def square(self):
403
"""
404
Return f*f.
405
406
EXAMPLES:
407
sage: f = ntl.ZZX([-1,0,1])
408
sage: f*f
409
[1 0 -2 0 1]
410
"""
411
sig_on()
412
return make_ZZX_sig_off(ZZX_square(&self.x))
413
414
def __pow__(ntl_ZZX self, long n, ignored):
415
"""
416
Return the n-th nonnegative power of self.
417
418
EXAMPLES:
419
sage: g = ntl.ZZX([-1,0,1])
420
sage: g**10
421
[1 0 -10 0 45 0 -120 0 210 0 -252 0 210 0 -120 0 45 0 -10 0 1]
422
"""
423
if n < 0:
424
raise NotImplementedError
425
import sage.groups.generic as generic
426
from copy import copy
427
return generic.power(self, n, copy(one_ZZX))
428
429
def __cmp__(ntl_ZZX self, ntl_ZZX other):
430
"""
431
Decide whether or not self and other are equal.
432
433
EXAMPLES:
434
sage: f = ntl.ZZX([1,2,3])
435
sage: g = ntl.ZZX([1,2,3,0])
436
sage: f == g
437
True
438
sage: g = ntl.ZZX([0,1,2,3])
439
sage: f == g
440
False
441
"""
442
if ZZX_equal(self.x, other.x):
443
return 0
444
return -1
445
446
def is_zero(self):
447
"""
448
Return True exactly if this polynomial is 0.
449
450
EXAMPLES:
451
sage: f = ntl.ZZX([0,0,0,0])
452
sage: f.is_zero()
453
True
454
sage: f = ntl.ZZX([0,0,1])
455
sage: f
456
[0 0 1]
457
sage: f.is_zero()
458
False
459
"""
460
return bool(ZZX_IsZero(self.x))
461
462
def is_one(self):
463
"""
464
Return True exactly if this polynomial is 1.
465
466
EXAMPLES:
467
sage: f = ntl.ZZX([1,1])
468
sage: f.is_one()
469
False
470
sage: f = ntl.ZZX([1])
471
sage: f.is_one()
472
True
473
"""
474
return bool(ZZX_IsOne(self.x))
475
476
def is_monic(self):
477
"""
478
Return True exactly if this polynomial is monic.
479
480
EXAMPLES:
481
sage: f = ntl.ZZX([2,0,0,1])
482
sage: f.is_monic()
483
True
484
sage: g = f.reverse()
485
sage: g.is_monic()
486
False
487
sage: g
488
[1 0 0 2]
489
"""
490
if ZZX_IsZero(self.x):
491
return False
492
cdef ZZ_c lc
493
lc = ZZX_LeadCoeff(self.x)
494
return <bint>ZZ_IsOne(lc)
495
496
# return bool(ZZX_is_monic(&self.x))
497
498
def __neg__(self):
499
"""
500
Return the negative of self.
501
EXAMPLES:
502
sage: f = ntl.ZZX([2,0,0,1])
503
sage: -f
504
[-2 0 0 -1]
505
"""
506
return make_ZZX(ZZX_neg(&self.x))
507
508
def left_shift(self, long n):
509
"""
510
Return the polynomial obtained by shifting all coefficients of
511
this polynomial to the left n positions.
512
513
EXAMPLES:
514
sage: f = ntl.ZZX([2,0,0,1])
515
sage: f
516
[2 0 0 1]
517
sage: f.left_shift(2)
518
[0 0 2 0 0 1]
519
sage: f.left_shift(5)
520
[0 0 0 0 0 2 0 0 1]
521
522
A negative left shift is a right shift.
523
sage: f.left_shift(-2)
524
[0 1]
525
"""
526
return make_ZZX(ZZX_left_shift(&self.x, n))
527
528
def right_shift(self, long n):
529
"""
530
Return the polynomial obtained by shifting all coefficients of
531
this polynomial to the right n positions.
532
533
EXAMPLES:
534
sage: f = ntl.ZZX([2,0,0,1])
535
sage: f
536
[2 0 0 1]
537
sage: f.right_shift(2)
538
[0 1]
539
sage: f.right_shift(5)
540
[]
541
sage: f.right_shift(-2)
542
[0 0 2 0 0 1]
543
"""
544
return make_ZZX(ZZX_right_shift(&self.x, n))
545
546
def content(self):
547
"""
548
Return the content of f, which has sign the same as the
549
leading coefficient of f. Also, our convention is that the
550
content of 0 is 0.
551
552
EXAMPLES:
553
sage: f = ntl.ZZX([2,0,0,2])
554
sage: f.content()
555
2
556
sage: f = ntl.ZZX([2,0,0,-2])
557
sage: f.content()
558
-2
559
sage: f = ntl.ZZX([6,12,3,9])
560
sage: f.content()
561
3
562
sage: f = ntl.ZZX([])
563
sage: f.content()
564
0
565
"""
566
cdef ntl_ZZ r = PY_NEW(ntl_ZZ)
567
ZZX_content(r.x, self.x)
568
return r
569
570
def primitive_part(self):
571
"""
572
Return the primitive part of f. Our convention is that the leading
573
coefficient of the primitive part is nonnegative, and the primitive
574
part of 0 is 0.
575
576
EXAMPLES:
577
sage: f = ntl.ZZX([6,12,3,9])
578
sage: f.primitive_part()
579
[2 4 1 3]
580
sage: f
581
[6 12 3 9]
582
sage: f = ntl.ZZX([6,12,3,-9])
583
sage: f
584
[6 12 3 -9]
585
sage: f.primitive_part()
586
[-2 -4 -1 3]
587
sage: f = ntl.ZZX()
588
sage: f.primitive_part()
589
[]
590
"""
591
return make_ZZX(ZZX_primitive_part(&self.x))
592
593
def pseudo_quo_rem(self, ntl_ZZX other):
594
r"""
595
Performs pseudo-division: computes q and r with deg(r) <
596
deg(b), and \code{LeadCoeff(b)\^(deg(a)-deg(b)+1) a = b q + r}.
597
Only the classical algorithm is used.
598
599
EXAMPLES:
600
sage: f = ntl.ZZX([0,1])
601
sage: g = ntl.ZZX([1,2,3])
602
sage: g.pseudo_quo_rem(f)
603
([2 3], [1])
604
sage: f = ntl.ZZX([1,1])
605
sage: g.pseudo_quo_rem(f)
606
([-1 3], [2])
607
"""
608
cdef ZZX_c *r, *q
609
try:
610
sig_on()
611
ZZX_pseudo_quo_rem(&self.x, &other.x, &r, &q)
612
return (make_ZZX(q), make_ZZX(r))
613
finally:
614
sig_off()
615
616
def gcd(self, ntl_ZZX other):
617
"""
618
Return the gcd d = gcd(a, b), where by convention the leading coefficient
619
of d is >= 0. We use a multi-modular algorithm.
620
621
EXAMPLES:
622
sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2
623
sage: g = ntl.ZZX([1,1,1])**3 * ntl.ZZX([1,2,3])
624
sage: f.gcd(g)
625
[1 2 3]
626
sage: g.gcd(f)
627
[1 2 3]
628
"""
629
sig_on()
630
return make_ZZX_sig_off(ZZX_gcd(&self.x, &other.x))
631
632
def lcm(self, ntl_ZZX other):
633
"""
634
Return the least common multiple of self and other.
635
636
EXAMPLES:
637
sage: x1 = ntl.ZZX([-1,0,0,1])
638
sage: x2 = ntl.ZZX([-1,0,0,0,0,0,1])
639
sage: x1.lcm(x2)
640
[-1 0 0 0 0 0 1]
641
"""
642
g = self.gcd(other)
643
return (self*other).quo_rem(g)[0]
644
645
def xgcd(self, ntl_ZZX other, proof=None):
646
"""
647
If self and other are coprime over the rationals, return r, s,
648
t such that r = s*self + t*other. Otherwise return 0. This
649
is \emph{not} the same as the \sage function on polynomials
650
over the integers, since here the return value r is always an
651
integer.
652
653
Here r is the resultant of a and b; if r != 0, then this
654
function computes s and t such that: a*s + b*t = r; otherwise
655
s and t are both 0. If proof = False (*not* the default),
656
then resultant computation may use a randomized strategy that
657
errors with probability no more than $2^{-80}$. The default is
658
default is proof=None, see proof.polynomial or sage.structure.proof,
659
but the global default is True), then this function may use a
660
randomized strategy that errors with probability no more than
661
$2^{-80}$.
662
663
664
EXAMPLES:
665
sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2
666
sage: g = ntl.ZZX([1,1,1])**3 * ntl.ZZX([1,2,3])
667
sage: f.xgcd(g) # nothing since they are not coprime
668
(0, [], [])
669
670
In this example the input quadratic polynomials have a common root modulo 13.
671
sage: f = ntl.ZZX([5,0,1])
672
sage: g = ntl.ZZX([18,0,1])
673
sage: f.xgcd(g)
674
(169, [-13], [13])
675
"""
676
proof = proof_flag(proof)
677
678
cdef ZZX_c *s, *t
679
cdef ZZ_c *r
680
try:
681
sig_on()
682
ZZX_xgcd(&self.x, &other.x, &r, &s, &t, proof)
683
return (make_ZZ(r), make_ZZX(s), make_ZZX(t))
684
finally:
685
sig_off()
686
687
def degree(self):
688
"""
689
Return the degree of this polynomial. The degree of the 0
690
polynomial is -1.
691
692
EXAMPLES:
693
sage: f = ntl.ZZX([5,0,1])
694
sage: f.degree()
695
2
696
sage: f = ntl.ZZX(range(100))
697
sage: f.degree()
698
99
699
sage: f = ntl.ZZX()
700
sage: f.degree()
701
-1
702
sage: f = ntl.ZZX([1])
703
sage: f.degree()
704
0
705
"""
706
return ZZX_deg(self.x)
707
708
def leading_coefficient(self):
709
"""
710
Return the leading coefficient of this polynomial.
711
712
EXAMPLES:
713
sage: f = ntl.ZZX([3,6,9])
714
sage: f.leading_coefficient()
715
9
716
sage: f = ntl.ZZX()
717
sage: f.leading_coefficient()
718
0
719
"""
720
cdef ntl_ZZ r = PY_NEW(ntl_ZZ)
721
r.x = ZZX_LeadCoeff(self.x)
722
return r
723
724
def constant_term(self):
725
"""
726
Return the constant coefficient of this polynomial.
727
728
EXAMPLES:
729
sage: f = ntl.ZZX([3,6,9])
730
sage: f.constant_term()
731
3
732
sage: f = ntl.ZZX()
733
sage: f.constant_term()
734
0
735
"""
736
cdef ntl_ZZ r = PY_NEW(ntl_ZZ)
737
r.x = ZZX_ConstTerm(self.x)
738
return r
739
740
def set_x(self):
741
"""
742
Set this polynomial to the monomial "x".
743
744
EXAMPLES:
745
sage: f = ntl.ZZX()
746
sage: f.set_x()
747
sage: f
748
[0 1]
749
sage: g = ntl.ZZX([0,1])
750
sage: f == g
751
True
752
753
Though f and g are equal, they are not the same objects in memory:
754
sage: f is g
755
False
756
"""
757
ZZX_set_x(&self.x)
758
759
def is_x(self):
760
"""
761
True if this is the polynomial "x".
762
763
EXAMPLES:
764
sage: f = ntl.ZZX()
765
sage: f.set_x()
766
sage: f.is_x()
767
True
768
sage: f = ntl.ZZX([0,1])
769
sage: f.is_x()
770
True
771
sage: f = ntl.ZZX([1])
772
sage: f.is_x()
773
False
774
"""
775
return bool(ZZX_is_x(&self.x))
776
777
def derivative(self):
778
"""
779
Return the derivative of this polynomial.
780
781
EXAMPLES:
782
sage: f = ntl.ZZX([1,7,0,13])
783
sage: f.derivative()
784
[7 0 39]
785
"""
786
return make_ZZX(ZZX_derivative(&self.x))
787
788
def reverse(self, hi=None):
789
"""
790
Return the polynomial obtained by reversing the coefficients
791
of this polynomial. If hi is set then this function behaves
792
as if this polynomial has degree hi.
793
794
EXAMPLES:
795
sage: f = ntl.ZZX([1,2,3,4,5])
796
sage: f.reverse()
797
[5 4 3 2 1]
798
sage: f.reverse(hi=10)
799
[0 0 0 0 0 0 5 4 3 2 1]
800
sage: f.reverse(hi=2)
801
[3 2 1]
802
sage: f.reverse(hi=-2)
803
[]
804
"""
805
if not (hi is None):
806
return make_ZZX(ZZX_reverse_hi(&self.x, int(hi)))
807
else:
808
return make_ZZX(ZZX_reverse(&self.x))
809
810
def truncate(self, long m):
811
"""
812
Return the truncation of this polynomial obtained by
813
removing all terms of degree >= m.
814
815
EXAMPLES:
816
sage: f = ntl.ZZX([1,2,3,4,5])
817
sage: f.truncate(3)
818
[1 2 3]
819
sage: f.truncate(8)
820
[1 2 3 4 5]
821
sage: f.truncate(1)
822
[1]
823
sage: f.truncate(0)
824
[]
825
sage: f.truncate(-1)
826
[]
827
sage: f.truncate(-5)
828
[]
829
"""
830
if m <= 0:
831
from copy import copy
832
return copy(zero_ZZX)
833
sig_on()
834
return make_ZZX_sig_off(ZZX_truncate(&self.x, m))
835
836
def multiply_and_truncate(self, ntl_ZZX other, long m):
837
"""
838
Return self*other but with terms of degree >= m removed.
839
840
EXAMPLES:
841
sage: f = ntl.ZZX([1,2,3,4,5])
842
sage: g = ntl.ZZX([10])
843
sage: f.multiply_and_truncate(g, 2)
844
[10 20]
845
sage: g.multiply_and_truncate(f, 2)
846
[10 20]
847
"""
848
if m <= 0:
849
from copy import copy
850
return copy(zero_ZZX)
851
return make_ZZX(ZZX_multiply_and_truncate(&self.x, &other.x, m))
852
853
def square_and_truncate(self, long m):
854
"""
855
Return self*self but with terms of degree >= m removed.
856
857
EXAMPLES:
858
sage: f = ntl.ZZX([1,2,3,4,5])
859
sage: f.square_and_truncate(4)
860
[1 4 10 20]
861
sage: (f*f).truncate(4)
862
[1 4 10 20]
863
"""
864
if m < 0:
865
from copy import copy
866
return copy(zero_ZZX)
867
return make_ZZX(ZZX_square_and_truncate(&self.x, m))
868
869
def invert_and_truncate(self, long m):
870
"""
871
Compute and return the inverse of self modulo $x^m$.
872
The constant term of self must be 1 or -1.
873
874
EXAMPLES:
875
sage: f = ntl.ZZX([1,2,3,4,5,6,7])
876
sage: f.invert_and_truncate(20)
877
[1 -2 1 0 0 0 0 8 -23 22 -7 0 0 0 64 -240 337 -210 49]
878
sage: g = f.invert_and_truncate(20)
879
sage: g * f
880
[1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -512 1344 -1176 343]
881
"""
882
if m < 0:
883
raise ArithmeticError, "m (=%s) must be positive"%m
884
n = self.constant_term()
885
if n != ntl_ZZ(1) and n != ntl_ZZ(-1):
886
raise ArithmeticError, \
887
"The constant term of self must be 1 or -1."
888
sig_on()
889
return make_ZZX_sig_off(ZZX_invert_and_truncate(&self.x, m))
890
891
def multiply_mod(self, ntl_ZZX other, ntl_ZZX modulus):
892
"""
893
Return self*other % modulus. The modulus must be monic with
894
deg(modulus) > 0, and self and other must have smaller degree.
895
896
EXAMPLES:
897
sage: modulus = ntl.ZZX([1,2,0,1]) # must be monic
898
sage: g = ntl.ZZX([-1,0,1])
899
sage: h = ntl.ZZX([3,7,13])
900
sage: h.multiply_mod(g, modulus)
901
[-10 -34 -36]
902
"""
903
sig_on()
904
return make_ZZX_sig_off(ZZX_multiply_mod(&self.x, &other.x, &modulus.x))
905
906
def trace_mod(self, ntl_ZZX modulus):
907
"""
908
Return the trace of this polynomial modulus the modulus.
909
The modulus must be monic, and of positive degree degree bigger
910
than the degree of self.
911
912
EXAMPLES:
913
sage: f = ntl.ZZX([1,2,0,3])
914
sage: mod = ntl.ZZX([5,3,-1,1,1])
915
sage: f.trace_mod(mod)
916
-37
917
"""
918
sig_on()
919
return make_ZZ_sig_off(ZZX_trace_mod(&self.x, &modulus.x))
920
921
def trace_list(self):
922
"""
923
Return the list of traces of the powers $x^i$ of the
924
monomial x modulo this polynomial for i = 0, ..., deg(f)-1.
925
This polynomial must be monic.
926
927
EXAMPLES:
928
sage: f = ntl.ZZX([1,2,0,3,0,1])
929
sage: f.trace_list()
930
[5, 0, -6, 0, 10]
931
932
The input polynomial must be monic or a ValueError is raised:
933
sage: f = ntl.ZZX([1,2,0,3,0,2])
934
sage: f.trace_list()
935
Traceback (most recent call last):
936
...
937
ValueError: polynomial must be monic.
938
"""
939
if not self.is_monic():
940
raise ValueError, "polynomial must be monic."
941
sig_on()
942
cdef char* t
943
t = ZZX_trace_list(&self.x)
944
return eval(string_delete(t).replace(' ', ','))
945
946
def resultant(self, ntl_ZZX other, proof=None):
947
"""
948
Return the resultant of self and other. If proof = False (the
949
default is proof=None, see proof.polynomial or sage.structure.proof,
950
but the global default is True), then this function may use a
951
randomized strategy that errors with probability no more than
952
$2^{-80}$.
953
954
EXAMPLES:
955
sage: f = ntl.ZZX([17,0,1,1])
956
sage: g = ntl.ZZX([34,-17,18,2])
957
sage: f.resultant(g)
958
1345873
959
sage: f.resultant(g, proof=False)
960
1345873
961
"""
962
proof = proof_flag(proof)
963
# NOTES: Within a factor of 2 in speed compared to MAGMA.
964
sig_on()
965
return make_ZZ_sig_off(ZZX_resultant(&self.x, &other.x, proof))
966
967
def norm_mod(self, ntl_ZZX modulus, proof=None):
968
"""
969
Return the norm of this polynomial modulo the modulus. The
970
modulus must be monic, and of positive degree strictly greater
971
than the degree of self. If proof=False (the default is
972
proof=None, see proof.polynomial or sage.structure.proof, but
973
the global default is proof=True) then it may use a randomized
974
strategy that errors with probability no more than $2^{-80}$.
975
976
EXAMPLE:
977
sage: f = ntl.ZZX([1,2,0,3])
978
sage: mod = ntl.ZZX([-5,2,0,0,1])
979
sage: f.norm_mod(mod)
980
-8846
981
982
The norm is the constant term of the characteristic polynomial.
983
sage: f.charpoly_mod(mod)
984
[-8846 -594 -60 14 1]
985
"""
986
proof = proof_flag(proof)
987
sig_on()
988
return make_ZZ_sig_off(ZZX_norm_mod(&self.x, &modulus.x, proof))
989
990
def discriminant(self, proof=None):
991
r"""
992
Return the discriminant of self, which is by definition
993
$$
994
(-1)^{m(m-1)/2} {\mbox{\tt resultant}}(a, a')/lc(a),
995
$$
996
where m = deg(a), and lc(a) is the leading coefficient of a.
997
If proof is False (the default is proof=None, see
998
proof.polynomial or sage.structure.proof, but the global
999
default is proof=True), then this function may use a
1000
randomized strategy that errors with probability no more than
1001
$2^{-80}$.
1002
1003
EXAMPLES:
1004
sage: f = ntl.ZZX([1,2,0,3])
1005
sage: f.discriminant()
1006
-339
1007
sage: f.discriminant(proof=False)
1008
-339
1009
"""
1010
proof = proof_flag(proof)
1011
sig_on()
1012
return make_ZZ_sig_off(ZZX_discriminant(&self.x, proof))
1013
1014
#def __call__(self, ntl_ZZ a):
1015
# sig_on()
1016
# return make_ZZ_sig_off(ZZX_polyeval(&self.x, a.x))
1017
1018
def charpoly_mod(self, ntl_ZZX modulus, proof=None):
1019
"""
1020
Return the characteristic polynomial of this polynomial modulo
1021
the modulus. The modulus must be monic of degree bigger than
1022
self. If proof=False (the default is proof=None, see
1023
proof.polynomial or sage.structure.proof, but the global
1024
default is proof=True), then this function may use a
1025
randomized strategy that errors with probability no more than
1026
$2^{-80}$.
1027
1028
EXAMPLES:
1029
sage: f = ntl.ZZX([1,2,0,3])
1030
sage: mod = ntl.ZZX([-5,2,0,0,1])
1031
sage: f.charpoly_mod(mod)
1032
[-8846 -594 -60 14 1]
1033
1034
"""
1035
proof = proof_flag(proof)
1036
sig_on()
1037
return make_ZZX_sig_off(ZZX_charpoly_mod(&self.x, &modulus.x, proof))
1038
1039
def minpoly_mod_noproof(self, ntl_ZZX modulus):
1040
"""
1041
Return the minimal polynomial of this polynomial modulo the
1042
modulus. The modulus must be monic of degree bigger than
1043
self. In all cases, this function may use a randomized
1044
strategy that errors with probability no more than $2^{-80}$.
1045
1046
EXAMPLES:
1047
sage: f = ntl.ZZX([0,0,1])
1048
sage: g = f*f
1049
sage: f.charpoly_mod(g)
1050
[0 0 0 0 1]
1051
1052
However, since $f^2 = 0$ modulo $g$, its minimal polynomial
1053
is of degree $2$.
1054
sage: f.minpoly_mod_noproof(g)
1055
[0 0 1]
1056
"""
1057
sig_on()
1058
return make_ZZX_sig_off(ZZX_minpoly_mod(&self.x, &modulus.x))
1059
1060
def clear(self):
1061
"""
1062
Reset this polynomial to 0. Changes this polynomial in place.
1063
1064
EXAMPLES:
1065
sage: f = ntl.ZZX([1,2,3])
1066
sage: f
1067
[1 2 3]
1068
sage: f.clear()
1069
sage: f
1070
[]
1071
"""
1072
ZZX_clear(&self.x)
1073
1074
def preallocate_space(self, long n):
1075
"""
1076
Pre-allocate spaces for n coefficients. The polynomial that f
1077
represents is unchanged. This is useful if you know you'll be
1078
setting coefficients up to n, so memory isn't re-allocated as
1079
the polynomial grows. (You might save a millisecond with this
1080
function.)
1081
1082
EXAMPLES:
1083
sage: f = ntl.ZZX([1,2,3])
1084
sage: f.preallocate_space(20)
1085
sage: f
1086
[1 2 3]
1087
sage: f[10]=5 # no new memory is allocated
1088
sage: f
1089
[1 2 3 0 0 0 0 0 0 0 5]
1090
"""
1091
sig_on()
1092
ZZX_preallocate_space(&self.x, n)
1093
sig_off()
1094
1095
def squarefree_decomposition(self):
1096
"""
1097
Returns the square-free decomposition of self (a partial
1098
factorization into square-free, relatively prime polynomials)
1099
as a list of 2-tuples, where the first element in each tuple
1100
is a factor, and the second is its exponent.
1101
Assumes that self is primitive.
1102
1103
EXAMPLES:
1104
sage: f = ntl.ZZX([0, 1, 2, 1])
1105
sage: f.squarefree_decomposition()
1106
[([0 1], 1), ([1 1], 2)]
1107
"""
1108
cdef ZZX_c** v
1109
cdef long* e
1110
cdef long i, n
1111
sig_on()
1112
ZZX_squarefree_decomposition(&v, &e, &n, &self.x)
1113
sig_off()
1114
F = []
1115
for i from 0 <= i < n:
1116
F.append((make_ZZX(v[i]), e[i]))
1117
sage_free(v)
1118
sage_free(e)
1119
return F
1120
1121
1122
one_ZZX = ntl_ZZX([1])
1123
zero_ZZX = ntl_ZZX()
1124
1125