/
polynomial_element.pyx
7810 lines (6422 loc) · 262 KB
/
polynomial_element.pyx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
Univariate Polynomial Base Class
AUTHORS:
- William Stein: first version.
- Martin Albrecht: Added singular coercion.
- Robert Bradshaw: Move Polynomial_generic_dense to Cython.
- Miguel Marco: Implemented resultant in the case where PARI fails.
- Simon King: Use a faster way of conversion from the base ring.
- Julian Rueth (2012-05-25,2014-05-09): Fixed is_squarefree() for imperfect
fields, fixed division without remainder over QQbar; added ``_cache_key``
for polynomials with unhashable coefficients
- Simon King (2013-10): Implement copying of :class:`PolynomialBaseringInjection`.
TESTS::
sage: R.<x> = ZZ[]
sage: f = x^5 + 2*x^2 + (-1)
sage: f == loads(dumps(f))
True
"""
#*****************************************************************************
# Copyright (C) 2007 William Stein <wstein@gmail.com>
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
cdef is_FractionField, is_RealField, is_ComplexField
cdef coerce_binop, generic_power, parent
cdef ZZ, QQ, RR, CC, RDF, CDF
import operator, copy, re
import sage.rings.rational
import sage.rings.integer
import polynomial_ring
import sage.rings.arith
#import sage.rings.ring_element
import sage.rings.integer_ring
import sage.rings.rational_field
import sage.rings.finite_rings.integer_mod_ring
import sage.rings.complex_field
import sage.rings.fraction_field_element
import sage.rings.infinity as infinity
#import sage.misc.misc as misc
from sage.misc.sage_eval import sage_eval
from sage.misc.latex import latex
from sage.structure.factorization import Factorization
from sage.structure.element import coerce_binop
from sage.interfaces.singular import singular as singular_default, is_SingularElement
from sage.libs.all import pari, pari_gen, PariError
from sage.rings.real_mpfr import RealField, is_RealField, RR
from sage.rings.complex_field import is_ComplexField, ComplexField
CC = ComplexField()
from sage.rings.real_double import is_RealDoubleField, RDF
from sage.rings.complex_double import is_ComplexDoubleField, CDF
from sage.rings.real_mpfi import is_RealIntervalField
from sage.structure.element import RingElement, generic_power, parent
from sage.structure.element cimport Element, RingElement, ModuleElement, MonoidElement
from sage.rings.rational_field import QQ, is_RationalField
from sage.rings.integer_ring import ZZ, is_IntegerRing
from sage.rings.integer cimport smallInteger
from sage.rings.fraction_field import is_FractionField
from sage.rings.padics.generic_nodes import is_pAdicRing, is_pAdicField
from sage.rings.integral_domain import is_IntegralDomain
from sage.structure.parent_gens cimport ParentWithGens
from sage.misc.derivative import multi_derivative
from sage.rings.arith import sort_complex_numbers_for_display
import polynomial_fateman
from sage.rings.integer cimport Integer
from sage.rings.ideal import is_Ideal
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing
from sage.misc.cachefunc import cached_function
from sage.categories.map cimport Map
from sage.categories.morphism cimport Morphism
cpdef is_Polynomial(f):
"""
Return True if f is of type univariate polynomial.
INPUT:
- ``f`` - an object
EXAMPLES::
sage: from sage.rings.polynomial.polynomial_element import is_Polynomial
sage: R.<x> = ZZ[]
sage: is_Polynomial(x^3 + x + 1)
True
sage: S.<y> = R[]
sage: f = y^3 + x*y -3*x; f
y^3 + x*y - 3*x
sage: is_Polynomial(f)
True
However this function does not return True for genuine multivariate
polynomial type objects or symbolic polynomials, since those are
not of the same data type as univariate polynomials::
sage: R.<x,y> = QQ[]
sage: f = y^3 + x*y -3*x; f
y^3 + x*y - 3*x
sage: is_Polynomial(f)
False
sage: var('x,y')
(x, y)
sage: f = y^3 + x*y -3*x; f
y^3 + x*y - 3*x
sage: is_Polynomial(f)
False
"""
return PY_TYPE_CHECK(f, Polynomial)
from polynomial_compiled cimport CompiledPolynomialFunction
from polydict import ETuple
cdef object is_AlgebraicRealField
cdef object is_AlgebraicField
cdef object is_AlgebraicField_common
cdef object NumberField_quadratic
cdef object is_ComplexIntervalField
cdef void late_import():
# A hack to avoid circular imports.
global is_AlgebraicRealField
global is_AlgebraicField
global is_AlgebraicField_common
global NumberField_quadratic
global is_ComplexIntervalField
if is_AlgebraicRealField is not None:
return
import sage.rings.qqbar
is_AlgebraicRealField = sage.rings.qqbar.is_AlgebraicRealField
is_AlgebraicField = sage.rings.qqbar.is_AlgebraicField
is_AlgebraicField_common = sage.rings.qqbar.is_AlgebraicField_common
import sage.rings.number_field.number_field
NumberField_quadratic = sage.rings.number_field.number_field.NumberField_quadratic
import sage.rings.complex_interval_field
is_ComplexIntervalField = sage.rings.complex_interval_field.is_ComplexIntervalField
cdef class Polynomial(CommutativeAlgebraElement):
"""
A polynomial.
EXAMPLE::
sage: R.<y> = QQ['y']
sage: S.<x> = R['x']
sage: f = x*y; f
y*x
sage: type(f)
<type 'sage.rings.polynomial.polynomial_element.Polynomial_generic_dense'>
sage: p = (y+1)^10; p(1)
1024
"""
def __init__(self, parent, is_gen = False, construct=False):
"""
The following examples illustrate creation of elements of
polynomial rings, and some basic arithmetic.
First we make a polynomial over the integers and do some
arithmetic::
sage: R.<x> = ZZ[]
sage: f = x^5 + 2*x^2 + (-1); f
x^5 + 2*x^2 - 1
sage: f^2
x^10 + 4*x^7 - 2*x^5 + 4*x^4 - 4*x^2 + 1
Next we do arithmetic in a sparse polynomial ring over the
integers::
sage: R.<x> = ZZ[ ]; R
Univariate Polynomial Ring in x over Integer Ring
sage: S.<Z> = R[ ]; S
Univariate Polynomial Ring in Z over Univariate Polynomial Ring in x over Integer Ring
sage: f = Z^3 + (x^2-2*x+1)*Z - 3; f
Z^3 + (x^2 - 2*x + 1)*Z - 3
sage: f*f
Z^6 + (2*x^2 - 4*x + 2)*Z^4 - 6*Z^3 + (x^4 - 4*x^3 + 6*x^2 - 4*x + 1)*Z^2 + (-6*x^2 + 12*x - 6)*Z + 9
sage: f^3 == f*f*f
True
"""
CommutativeAlgebraElement.__init__(self, parent)
self._is_gen = is_gen
def _dict_to_list(self, x, zero):
if len(x) == 0:
return []
n = max(x.keys())
if PY_TYPE_CHECK(n, tuple): # a mpoly dict
n = n[0]
v = [zero] * (n+1)
for i, z in x.iteritems():
v[i[0]] = z
else:
v = [zero] * (n+1)
for i, z in x.iteritems():
v[i] = z
return v
cpdef ModuleElement _add_(self, ModuleElement right):
cdef Py_ssize_t i, min
x = self.list()
y = right.list()
if len(x) > len(y):
min = len(y)
high = x[min:]
elif len(x) < len(y):
min = len(x)
high = y[min:]
else:
min = len(x)
high = []
low = [x[i] + y[i] for i from 0 <= i < min]
return self._parent(low + high)
cpdef ModuleElement _neg_(self):
return self._parent([-x for x in self.list()])
def plot(self, xmin=None, xmax=None, *args, **kwds):
"""
Return a plot of this polynomial.
INPUT:
- ``xmin`` - float
- ``xmax`` - float
- ``*args, **kwds`` - passed to either plot or
point
OUTPUT: returns a graphic object.
EXAMPLES::
sage: x = polygen(GF(389))
sage: plot(x^2 + 1, rgbcolor=(0,0,1))
Graphics object consisting of 1 graphics primitive
sage: x = polygen(QQ)
sage: plot(x^2 + 1, rgbcolor=(1,0,0))
Graphics object consisting of 1 graphics primitive
"""
R = self.base_ring()
from sage.plot.all import plot, point, line
if R.characteristic() == 0:
if xmin is None and xmax is None:
(xmin, xmax) = (-1,1)
elif xmin is None or xmax is None:
raise AttributeError("must give both plot endpoints")
return plot(self.__call__, (xmin, xmax), *args, **kwds)
else:
if R.is_finite():
v = list(R)
v.sort()
w = dict([(v[i],i) for i in range(len(v))])
z = [(i, w[self(v[i])]) for i in range(len(v))]
return point(z, *args, **kwds)
raise NotImplementedError("plotting of polynomials over %s not implemented"%R)
cpdef ModuleElement _lmul_(self, RingElement left):
"""
Multiply self on the left by a scalar.
EXAMPLE::
sage: R.<x> = ZZ[]
sage: f = (x^3 + x + 5)
sage: f._lmul_(7)
7*x^3 + 7*x + 35
sage: 7*f
7*x^3 + 7*x + 35
"""
# todo -- should multiply individual coefficients??
# that could be in derived class.
# Note that we are guaranteed that right is in the base ring, so this could be fast.
if left == 0:
return self.parent().zero_element()
return self.parent()(left) * self
cpdef ModuleElement _rmul_(self, RingElement right):
"""
Multiply self on the right by a scalar.
EXAMPLE::
sage: R.<x> = ZZ[]
sage: f = (x^3 + x + 5)
sage: f._rmul_(7)
7*x^3 + 7*x + 35
sage: f*7
7*x^3 + 7*x + 35
"""
# todo -- Should multiply individual coefficients??
# that could be in derived class.
# Note that we are guaranteed that right is in the base ring, so this could be fast.
if right == 0:
return self.parent().zero_element()
return self * self.parent()(right)
def subs(self, *x, **kwds):
r"""
Identical to self(\*x).
See the docstring for ``self.__call__``.
EXAMPLES::
sage: R.<x> = QQ[]
sage: f = x^3 + x - 3
sage: f.subs(x=5)
127
sage: f.subs(5)
127
sage: f.subs({x:2})
7
sage: f.subs({})
x^3 + x - 3
sage: f.subs({'x':2})
Traceback (most recent call last):
...
TypeError: keys do not match self's parent
"""
if len(x) == 1 and isinstance(x[0], dict):
g = self.parent().gen()
if g in x[0]:
return self(x[0][g])
elif len(x[0]) > 0:
raise TypeError("keys do not match self's parent")
return self
return self.__call__(*x, **kwds)
substitute = subs
def __call__(self, *x, **kwds):
"""
Evaluate polynomial at x=a.
INPUT:
- ``x``:
- ring element a; need not be in the
coefficient ring of the polynomial.
- a dictionary for kwds:value pairs. If the variable name
of the polynomial is a kwds it is substituted in;
otherwise this polynomial is returned unchanged.
OUTPUT: the value of f at a.
EXAMPLES::
sage: R.<x> = QQ[]
sage: f = x/2 - 5
sage: f(3)
-7/2
sage: R.<x> = ZZ[]
sage: f = (x-1)^5
sage: f(2/3)
-1/243
We evaluate a polynomial over a quaternion algebra::
sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-1)
sage: R.<w> = PolynomialRing(A,sparse=True)
sage: f = i*j*w^5 - 13*i*w^2 + (i+j)*w + i
sage: f(i+j+1)
24 + 26*i - 10*j - 25*k
sage: w = i+j+1; i*j*w^5 - 13*i*w^2 + (i+j)*w + i
24 + 26*i - 10*j - 25*k
The parent ring of the answer always "starts" with the parent of
the object at which we are evaluating. Thus, e.g., if we input a
matrix, we are guaranteed to get a matrix out, though the base ring
of that matrix may change depending on the base of the polynomial
ring. ::
sage: R.<x> = QQ[]
sage: f = R(2/3)
sage: a = matrix(ZZ,2)
sage: b = f(a); b
[2/3 0]
[ 0 2/3]
sage: b.parent()
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
sage: f = R(1)
sage: b = f(a); b
[1 0]
[0 1]
sage: b.parent()
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
::
sage: R.<w> = GF(17)[]
sage: f = w^3 + 3*w +2
sage: f(5)
6
sage: f(w=5)
6
sage: f(x=10) # x isn't mentioned
w^3 + 3*w + 2
Nested polynomial ring elements can be called like multi-variate
polynomials. ::
sage: R.<x> = QQ[]; S.<y> = R[]
sage: f = x+y*x+y^2
sage: f.parent()
Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field
sage: f(2)
3*x + 4
sage: f(2,4)
16
sage: f(y=2,x=4)
16
sage: f(2,x=4)
16
sage: f(2,x=4,z=5)
16
sage: f(2,4, z=10)
16
sage: f(y=x)
2*x^2 + x
sage: f(x=y)
2*y^2 + y
Polynomial ring elements can also, like multi-variate
polynomials, be called with an argument that is a list or
tuple containing the values to be substituted, though it is
perhaps more natural to just unpack the list::
sage: f([2]) # calling with a list
3*x + 4
sage: f((2,)) # calling with a tuple
3*x + 4
sage: f(*[2]) # unpacking the list to call normally
3*x + 4
The following results in an element of the symbolic ring. ::
sage: f(x=sqrt(2))
(y + sqrt(2))*y + sqrt(2)
::
sage: R.<t> = PowerSeriesRing(QQ, 't'); S.<x> = R[]
sage: f = 1 + x*t^2 + 3*x*t^4
sage: f(2)
1 + 2*t^2 + 6*t^4
sage: f(2, 1/2)
15/8
Some special cases are optimized. ::
sage: R.<x> = PolynomialRing(QQ, sparse=True)
sage: f = x^3-2*x
sage: f(x) is f
True
sage: f(1/x)
(-2*x^2 + 1)/x^3
sage: f = x^100 + 3
sage: f(0)
3
sage: parent(f(0))
Rational Field
sage: parent(f(Qp(5)(0)))
5-adic Field with capped relative precision 20
TESTS:
The following shows that :trac:`2360` is indeed fixed. ::
sage: R.<x,y> = ZZ[]
sage: P.<a> = ZZ[]
sage: e = [x^2,y^3]
sage: f = 6*a^4
sage: f(x)
6*x^4
sage: f(e)
Traceback (most recent call last):
...
TypeError: Wrong number of arguments
sage: f(x)
6*x^4
The following shows that :trac:`9006` is also fixed. ::
sage: f = ZZ['x'](1000000 * [1])
sage: f(1)
1000000
The following test came up in :trac:`9051`::
sage: Cif = ComplexIntervalField(64)
sage: R.<x> = Cif[]
sage: f = 2*x-1
sage: jj = Cif(RIF(0,2))
sage: f(jj).center(), f(jj).diameter()
(1.00000000000000000, 4.00000000000000000)
The following failed before the patch to :trac:`3979`
::
sage: R.<x> = ZZ[]
sage: S.<y> = R[]
sage: g = x*y + 1
sage: g(x=3)
3*y + 1
AUTHORS:
- David Joyner (2005-04-10)
- William Stein (2006-01-22): change so parent is determined by the
arithmetic
- William Stein (2007-03-24): fix parent being determined in the
constant case!
- Robert Bradshaw (2007-04-09): add support for nested calling
- Tom Boothby (2007-05-01): evaluation done by
CompiledPolynomialFunction
- William Stein (2007-06-03): add support for keyword arguments.
- Francis Clarke (2012-08-26): fix keyword substitution in the
leading coefficient.
"""
cdef long i, d = self.degree()
if kwds:
P = self.parent()
name = P.variable_name()
if name in kwds:
if len(x) > 0:
raise ValueError("must not specify both a keyword and positional argument")
a = self(kwds[name])
del kwds[name]
try:
return a(**kwds)
except TypeError:
return a
elif len(x) > 0:
a = self(*x)
try:
return a(**kwds)
except TypeError:
return a
else:
try:
result = self[d](**kwds)
except TypeError:
result = self[d]
a = P.gen()
i = d - 1
while i >= 0:
try:
s = self[i](**kwds)
except TypeError:
s = self[i]
result = result * a + s
i -= 1
return result
if len(x) == 0:
return self
if isinstance(x[0], (list, tuple)):
x = x[0]
a = x[0]
result = self[d]
if len(x) > 1:
other_args = x[1:]
try: #if hasattr(result, '__call__'):
result = result(other_args)
except TypeError: #else:
raise TypeError("Wrong number of arguments")
if d == -1:
try:
return a.parent().zero_element()
except AttributeError:
pass
try: # for things like the interface to the PARI C library
return a.parent()(0)
except AttributeError:
return result
if d == 0:
try:
return a.parent().one_element() * result
except AttributeError:
pass
try: # for things like the interface to the PARI C library
return a.parent()(1) * result
except AttributeError:
return result
if parent(a) is self._parent and a.is_gen():
return self
elif is_FractionField(parent(a)):
try:
a_inverse = ~a
if a_inverse.denominator() == 1:
a_inverse = a_inverse.numerator()
return self.reverse()(a_inverse) / a_inverse**self.degree()
except AttributeError:
pass
i = d - 1
if len(x) > 1:
while i >= 0:
result = result * a + self[i](other_args)
i -= 1
elif not a and PY_TYPE_CHECK(a, Element) and a.parent().is_exact(): #without the exactness test we can run into trouble with interval fields.
c = self[0]
return c + c*a
elif (d < 4 or d > 50000) and self._compiled is None:
while i >= 0:
result = result * a + self[i]
i -= 1
else:
if self._compiled is None:
self._compiled = CompiledPolynomialFunction(self.list())
result = self._compiled.eval(a)
return result
def _compile(self):
# For testing
self._compiled = CompiledPolynomialFunction(self.list())
return self._compiled
def _get_compiled(self):
# For testing
return self._compiled
def _fast_float_(self, *vars):
"""
Returns a quickly-evaluating function on floats.
EXAMPLE::
sage: R.<t> = QQ[]
sage: f = t^3-t
sage: ff = f._fast_float_()
sage: ff(10)
990.0
Horner's method is used::
sage: f = (t+10)^3; f
t^3 + 30*t^2 + 300*t + 1000
sage: list(f._fast_float_())
['load 0', 'push 30.0', 'add', 'load 0', 'mul', 'push 300.0', 'add', 'load 0', 'mul', 'push 1000.0', 'add']
TESTS::
sage: f = t + 2 - t
sage: ff = f._fast_float_()
sage: ff(3)
2.0
sage: list(f._fast_float_())
['push 2.0']
sage: f = t - t
sage: ff = f._fast_float_()
sage: ff(3)
0.0
sage: list(f._fast_float_())
['push 0.0']
"""
from sage.ext.fast_eval import fast_float_arg, fast_float_constant
var = (<ParentWithGens>self._parent)._names[0]
if len(vars) == 0:
x = fast_float_arg(0)
elif var in vars:
x = fast_float_arg(list(vars).index(var))
else:
raise ValueError("free variable: %s" % var)
cdef int i, d = self.degree()
expr = x
coeff = self[d]
if d <= 0:
return fast_float_constant(coeff)
if coeff != 1:
expr *= fast_float_constant(coeff)
for i from d > i >= 0:
coeff = self[i]
if coeff:
expr += fast_float_constant(coeff)
if i > 0:
expr *= x
return expr
def _fast_callable_(self, etb):
r"""
Given an ExpressionTreeBuilder, return an Expression representing
this value.
EXAMPLES::
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
sage: etb = ExpressionTreeBuilder(vars=['t'])
sage: R.<t> = QQ[]
sage: v = R.random_element(6); v
-t^6 - 12*t^5 + 1/2*t^4 - 1/95*t^3 - 1/2*t^2 - 4
sage: v._fast_callable_(etb)
add(mul(mul(add(mul(add(mul(add(mul(add(mul(v_0, -1), -12), v_0), 1/2), v_0), -1/95), v_0), -1/2), v_0), v_0), -4)
TESTS::
sage: R(2)._fast_callable_(etb)
2
sage: R(0)._fast_callable_(etb)
0
sage: fast_callable(R(2))(3)
2
"""
x = etb.var(self.variable_name())
expr = x
cdef int i, d = self.degree()
coeff = self[d]
# We handle polynomial rings like QQ['x']['y']; that gives us some
# slowdown. Optimize away some of that:
if len(etb._vars) == 1:
# OK, we're in the (very common) univariate case.
coeff_maker = etb.constant
else:
# There may be variables in our coefficients...
coeff_maker = etb.make
if d <= 0:
return coeff_maker(coeff)
if coeff != 1:
expr *= coeff_maker(coeff)
for i from d > i >= 0:
coeff = self[i]
if coeff:
expr += coeff_maker(coeff)
if i > 0:
expr *= x
return expr
cdef int _cmp_c_impl(self, Element other) except -2:
"""
Compare the two polynomials self and other.
We order polynomials first by degree, then in dictionary order
starting with the coefficient of largest degree.
EXAMPLES::
sage: R.<x> = QQ['x']
sage: 3*x^3 + 5 > 10*x^2 + 19
True
sage: x^2 - 2*x - 1 < x^2 - 1
True
sage: x^2 - 2*x - 1 > x^2 - 1
False
sage: R(-1) < 0
False
sage: x^3 - 3 > 393939393
True
"""
d1 = self.degree(); d2 = other.degree()
c = cmp(d1, d2)
if c: return c
for i in reversed(xrange(d1+1)):
c = cmp(self[i], other[i])
if c: return c
return 0
def __richcmp__(left, right, int op):
return (<Element>left)._richcmp(right, op)
def __nonzero__(self):
"""
EXAMPLES::
sage: P = PolynomialRing(ZZ,'x')(0)
sage: bool(P)
False
sage: P = PolynomialRing(ZZ, 'x')([1,2,3])
sage: bool(P)
True
"""
return self.degree() >= 0
def __getitem__(self, n):
raise NotImplementedError
def __iter__(self):
return iter(self.list())
def _cache_key(self):
"""
Return a hashable key which identifies this element.
EXAMPLES::
sage: K.<u> = Qq(4)
sage: R.<x> = K[]
sage: f = x
sage: hash(f)
Traceback (most recent call last):
...
TypeError: unhashable type: 'sage.rings.padics.padic_ZZ_pX_CR_element.pAdicZZpXCRElement'
sage: f._cache_key()
(..., (0, 1 + O(2^20)))
sage: @cached_function
....: def foo(t): return t
....:
sage: foo(x)
(1 + O(2^20))*x
"""
return (self.parent(), tuple(self))
# you may have to replicate this boilerplate code in derived classes if you override
# __richcmp__. The python documentation at http://docs.python.org/api/type-structs.html
# explains how __richcmp__, __hash__, and __cmp__ are tied together.
def __hash__(self):
return self._hash_c()
cdef long _hash_c(self) except -1:
"""
This hash incorporates the variable name in an effort to respect
the obvious inclusions into multi-variable polynomial rings.
The tuple algorithm is borrowed from
http://effbot.org/zone/python-hash.htm.
EXAMPLES::
sage: R.<x>=ZZ[]
sage: hash(R(1))==hash(1) # respect inclusions of the integers
True
sage: hash(R.0)==hash(FractionField(R).0) # respect inclusions into the fraction field
True
sage: R.<x>=QQ[]
sage: hash(R(1/2))==hash(1/2) # respect inclusions of the rationals
True
sage: hash(R.0)==hash(FractionField(R).0) # respect inclusions into the fraction field
True
sage: R.<x>=IntegerModRing(11)[]
sage: hash(R.0)==hash(FractionField(R).0) # respect inclusions into the fraction field
True
TESTS:
Verify that :trac:`16251` has been resolved, i.e., polynomials with
unhashable coefficients are unhashable::
sage: K.<a> = Qq(9)
sage: R.<t> = K[]
sage: hash(t)
Traceback (most recent call last):
...
TypeError: unhashable type: 'sage.rings.padics.padic_ZZ_pX_CR_element.pAdicZZpXCRElement'
"""
cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap
cdef long result_mon
cdef long c_hash
cdef long var_name_hash
cdef int i
for i from 0<= i <= self.degree():
if i == 1:
# we delay the hashing until now to not waste it on a constant poly
var_name_hash = hash((<ParentWithGens>self._parent)._names[0])
# I'm assuming (incorrectly) that hashes of zero indicate that the element is 0.
# This assumption is not true, but I think it is true enough for the purposes and it
# it allows us to write fast code that omits terms with 0 coefficients. This is
# important if we want to maintain the '==' relationship with sparse polys.
c_hash = hash(self[i])
if c_hash != 0:
if i == 0:
result += c_hash
else:
# Hash (self[i], generator, i) as a tuple according to the algorithm.
result_mon = c_hash
result_mon = (1000003 * result_mon) ^ var_name_hash
result_mon = (1000003 * result_mon) ^ i
result += result_mon
if result == -1:
return -2
return result
def __float__(self):
if self.degree() > 0:
raise TypeError("cannot coerce nonconstant polynomial to float")
return float(self[0])
def __int__(self):
if self.degree() > 0:
raise TypeError("cannot coerce nonconstant polynomial to int")
return int(self[0])
def _im_gens_(self, codomain, im_gens):
"""
EXAMPLES::
sage: R.<x> = ZZ[]
sage: H = Hom(R, QQ); H
Set of Homomorphisms from Univariate Polynomial Ring in x over Integer Ring to Rational Field
sage: f = H([5]); f
Ring morphism:
From: Univariate Polynomial Ring in x over Integer Ring
To: Rational Field
Defn: x |--> 5
sage: f(x)
5
sage: f(x^2 + 3)
28
"""
a = im_gens[0]
P = a.parent()
d = self.degree()
result = P._coerce_(self[d])
i = d - 1
while i >= 0:
result = result * a + P._coerce_(self[i])
i -= 1
return result
def _integer_(self, ZZ):
r"""
EXAMPLES::
sage: k = GF(47)
sage: R.<x> = PolynomialRing(k)
sage: ZZ(R(45))
45
sage: ZZ(3*x + 45)
Traceback (most recent call last):
...
TypeError: cannot coerce nonconstant polynomial
"""
if self.degree() > 0:
raise TypeError("cannot coerce nonconstant polynomial")
return ZZ(self[0])
def _rational_(self):
r"""
EXAMPLES::
sage: R.<x> = PolynomialRing(QQ)
sage: QQ(R(45/4))
45/4
sage: QQ(3*x + 45)
Traceback (most recent call last):
...
TypeError: not a constant polynomial
"""
if self.degree() > 0: