Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/numpy/polynomial/chebyshev.py
7763 views
1
"""
2
====================================================
3
Chebyshev Series (:mod:`numpy.polynomial.chebyshev`)
4
====================================================
5
6
This module provides a number of objects (mostly functions) useful for
7
dealing with Chebyshev series, including a `Chebyshev` class that
8
encapsulates the usual arithmetic operations. (General information
9
on how this module represents and works with such polynomials is in the
10
docstring for its "parent" sub-package, `numpy.polynomial`).
11
12
Classes
13
-------
14
15
.. autosummary::
16
:toctree: generated/
17
18
Chebyshev
19
20
21
Constants
22
---------
23
24
.. autosummary::
25
:toctree: generated/
26
27
chebdomain
28
chebzero
29
chebone
30
chebx
31
32
Arithmetic
33
----------
34
35
.. autosummary::
36
:toctree: generated/
37
38
chebadd
39
chebsub
40
chebmulx
41
chebmul
42
chebdiv
43
chebpow
44
chebval
45
chebval2d
46
chebval3d
47
chebgrid2d
48
chebgrid3d
49
50
Calculus
51
--------
52
53
.. autosummary::
54
:toctree: generated/
55
56
chebder
57
chebint
58
59
Misc Functions
60
--------------
61
62
.. autosummary::
63
:toctree: generated/
64
65
chebfromroots
66
chebroots
67
chebvander
68
chebvander2d
69
chebvander3d
70
chebgauss
71
chebweight
72
chebcompanion
73
chebfit
74
chebpts1
75
chebpts2
76
chebtrim
77
chebline
78
cheb2poly
79
poly2cheb
80
chebinterpolate
81
82
See also
83
--------
84
`numpy.polynomial`
85
86
Notes
87
-----
88
The implementations of multiplication, division, integration, and
89
differentiation use the algebraic identities [1]_:
90
91
.. math::
92
T_n(x) = \\frac{z^n + z^{-n}}{2} \\\\
93
z\\frac{dx}{dz} = \\frac{z - z^{-1}}{2}.
94
95
where
96
97
.. math:: x = \\frac{z + z^{-1}}{2}.
98
99
These identities allow a Chebyshev series to be expressed as a finite,
100
symmetric Laurent series. In this module, this sort of Laurent series
101
is referred to as a "z-series."
102
103
References
104
----------
105
.. [1] A. T. Benjamin, et al., "Combinatorial Trigonometry with Chebyshev
106
Polynomials," *Journal of Statistical Planning and Inference 14*, 2008
107
(https://web.archive.org/web/20080221202153/https://www.math.hmc.edu/~benjamin/papers/CombTrig.pdf, pg. 4)
108
109
"""
110
import numpy as np
111
import numpy.linalg as la
112
from numpy.core.multiarray import normalize_axis_index
113
114
from . import polyutils as pu
115
from ._polybase import ABCPolyBase
116
117
__all__ = [
118
'chebzero', 'chebone', 'chebx', 'chebdomain', 'chebline', 'chebadd',
119
'chebsub', 'chebmulx', 'chebmul', 'chebdiv', 'chebpow', 'chebval',
120
'chebder', 'chebint', 'cheb2poly', 'poly2cheb', 'chebfromroots',
121
'chebvander', 'chebfit', 'chebtrim', 'chebroots', 'chebpts1',
122
'chebpts2', 'Chebyshev', 'chebval2d', 'chebval3d', 'chebgrid2d',
123
'chebgrid3d', 'chebvander2d', 'chebvander3d', 'chebcompanion',
124
'chebgauss', 'chebweight', 'chebinterpolate']
125
126
chebtrim = pu.trimcoef
127
128
#
129
# A collection of functions for manipulating z-series. These are private
130
# functions and do minimal error checking.
131
#
132
133
def _cseries_to_zseries(c):
134
"""Convert Chebyshev series to z-series.
135
136
Convert a Chebyshev series to the equivalent z-series. The result is
137
never an empty array. The dtype of the return is the same as that of
138
the input. No checks are run on the arguments as this routine is for
139
internal use.
140
141
Parameters
142
----------
143
c : 1-D ndarray
144
Chebyshev coefficients, ordered from low to high
145
146
Returns
147
-------
148
zs : 1-D ndarray
149
Odd length symmetric z-series, ordered from low to high.
150
151
"""
152
n = c.size
153
zs = np.zeros(2*n-1, dtype=c.dtype)
154
zs[n-1:] = c/2
155
return zs + zs[::-1]
156
157
158
def _zseries_to_cseries(zs):
159
"""Convert z-series to a Chebyshev series.
160
161
Convert a z series to the equivalent Chebyshev series. The result is
162
never an empty array. The dtype of the return is the same as that of
163
the input. No checks are run on the arguments as this routine is for
164
internal use.
165
166
Parameters
167
----------
168
zs : 1-D ndarray
169
Odd length symmetric z-series, ordered from low to high.
170
171
Returns
172
-------
173
c : 1-D ndarray
174
Chebyshev coefficients, ordered from low to high.
175
176
"""
177
n = (zs.size + 1)//2
178
c = zs[n-1:].copy()
179
c[1:n] *= 2
180
return c
181
182
183
def _zseries_mul(z1, z2):
184
"""Multiply two z-series.
185
186
Multiply two z-series to produce a z-series.
187
188
Parameters
189
----------
190
z1, z2 : 1-D ndarray
191
The arrays must be 1-D but this is not checked.
192
193
Returns
194
-------
195
product : 1-D ndarray
196
The product z-series.
197
198
Notes
199
-----
200
This is simply convolution. If symmetric/anti-symmetric z-series are
201
denoted by S/A then the following rules apply:
202
203
S*S, A*A -> S
204
S*A, A*S -> A
205
206
"""
207
return np.convolve(z1, z2)
208
209
210
def _zseries_div(z1, z2):
211
"""Divide the first z-series by the second.
212
213
Divide `z1` by `z2` and return the quotient and remainder as z-series.
214
Warning: this implementation only applies when both z1 and z2 have the
215
same symmetry, which is sufficient for present purposes.
216
217
Parameters
218
----------
219
z1, z2 : 1-D ndarray
220
The arrays must be 1-D and have the same symmetry, but this is not
221
checked.
222
223
Returns
224
-------
225
226
(quotient, remainder) : 1-D ndarrays
227
Quotient and remainder as z-series.
228
229
Notes
230
-----
231
This is not the same as polynomial division on account of the desired form
232
of the remainder. If symmetric/anti-symmetric z-series are denoted by S/A
233
then the following rules apply:
234
235
S/S -> S,S
236
A/A -> S,A
237
238
The restriction to types of the same symmetry could be fixed but seems like
239
unneeded generality. There is no natural form for the remainder in the case
240
where there is no symmetry.
241
242
"""
243
z1 = z1.copy()
244
z2 = z2.copy()
245
lc1 = len(z1)
246
lc2 = len(z2)
247
if lc2 == 1:
248
z1 /= z2
249
return z1, z1[:1]*0
250
elif lc1 < lc2:
251
return z1[:1]*0, z1
252
else:
253
dlen = lc1 - lc2
254
scl = z2[0]
255
z2 /= scl
256
quo = np.empty(dlen + 1, dtype=z1.dtype)
257
i = 0
258
j = dlen
259
while i < j:
260
r = z1[i]
261
quo[i] = z1[i]
262
quo[dlen - i] = r
263
tmp = r*z2
264
z1[i:i+lc2] -= tmp
265
z1[j:j+lc2] -= tmp
266
i += 1
267
j -= 1
268
r = z1[i]
269
quo[i] = r
270
tmp = r*z2
271
z1[i:i+lc2] -= tmp
272
quo /= scl
273
rem = z1[i+1:i-1+lc2].copy()
274
return quo, rem
275
276
277
def _zseries_der(zs):
278
"""Differentiate a z-series.
279
280
The derivative is with respect to x, not z. This is achieved using the
281
chain rule and the value of dx/dz given in the module notes.
282
283
Parameters
284
----------
285
zs : z-series
286
The z-series to differentiate.
287
288
Returns
289
-------
290
derivative : z-series
291
The derivative
292
293
Notes
294
-----
295
The zseries for x (ns) has been multiplied by two in order to avoid
296
using floats that are incompatible with Decimal and likely other
297
specialized scalar types. This scaling has been compensated by
298
multiplying the value of zs by two also so that the two cancels in the
299
division.
300
301
"""
302
n = len(zs)//2
303
ns = np.array([-1, 0, 1], dtype=zs.dtype)
304
zs *= np.arange(-n, n+1)*2
305
d, r = _zseries_div(zs, ns)
306
return d
307
308
309
def _zseries_int(zs):
310
"""Integrate a z-series.
311
312
The integral is with respect to x, not z. This is achieved by a change
313
of variable using dx/dz given in the module notes.
314
315
Parameters
316
----------
317
zs : z-series
318
The z-series to integrate
319
320
Returns
321
-------
322
integral : z-series
323
The indefinite integral
324
325
Notes
326
-----
327
The zseries for x (ns) has been multiplied by two in order to avoid
328
using floats that are incompatible with Decimal and likely other
329
specialized scalar types. This scaling has been compensated by
330
dividing the resulting zs by two.
331
332
"""
333
n = 1 + len(zs)//2
334
ns = np.array([-1, 0, 1], dtype=zs.dtype)
335
zs = _zseries_mul(zs, ns)
336
div = np.arange(-n, n+1)*2
337
zs[:n] /= div[:n]
338
zs[n+1:] /= div[n+1:]
339
zs[n] = 0
340
return zs
341
342
#
343
# Chebyshev series functions
344
#
345
346
347
def poly2cheb(pol):
348
"""
349
Convert a polynomial to a Chebyshev series.
350
351
Convert an array representing the coefficients of a polynomial (relative
352
to the "standard" basis) ordered from lowest degree to highest, to an
353
array of the coefficients of the equivalent Chebyshev series, ordered
354
from lowest to highest degree.
355
356
Parameters
357
----------
358
pol : array_like
359
1-D array containing the polynomial coefficients
360
361
Returns
362
-------
363
c : ndarray
364
1-D array containing the coefficients of the equivalent Chebyshev
365
series.
366
367
See Also
368
--------
369
cheb2poly
370
371
Notes
372
-----
373
The easy way to do conversions between polynomial basis sets
374
is to use the convert method of a class instance.
375
376
Examples
377
--------
378
>>> from numpy import polynomial as P
379
>>> p = P.Polynomial(range(4))
380
>>> p
381
Polynomial([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])
382
>>> c = p.convert(kind=P.Chebyshev)
383
>>> c
384
Chebyshev([1. , 3.25, 1. , 0.75], domain=[-1., 1.], window=[-1., 1.])
385
>>> P.chebyshev.poly2cheb(range(4))
386
array([1. , 3.25, 1. , 0.75])
387
388
"""
389
[pol] = pu.as_series([pol])
390
deg = len(pol) - 1
391
res = 0
392
for i in range(deg, -1, -1):
393
res = chebadd(chebmulx(res), pol[i])
394
return res
395
396
397
def cheb2poly(c):
398
"""
399
Convert a Chebyshev series to a polynomial.
400
401
Convert an array representing the coefficients of a Chebyshev series,
402
ordered from lowest degree to highest, to an array of the coefficients
403
of the equivalent polynomial (relative to the "standard" basis) ordered
404
from lowest to highest degree.
405
406
Parameters
407
----------
408
c : array_like
409
1-D array containing the Chebyshev series coefficients, ordered
410
from lowest order term to highest.
411
412
Returns
413
-------
414
pol : ndarray
415
1-D array containing the coefficients of the equivalent polynomial
416
(relative to the "standard" basis) ordered from lowest order term
417
to highest.
418
419
See Also
420
--------
421
poly2cheb
422
423
Notes
424
-----
425
The easy way to do conversions between polynomial basis sets
426
is to use the convert method of a class instance.
427
428
Examples
429
--------
430
>>> from numpy import polynomial as P
431
>>> c = P.Chebyshev(range(4))
432
>>> c
433
Chebyshev([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])
434
>>> p = c.convert(kind=P.Polynomial)
435
>>> p
436
Polynomial([-2., -8., 4., 12.], domain=[-1., 1.], window=[-1., 1.])
437
>>> P.chebyshev.cheb2poly(range(4))
438
array([-2., -8., 4., 12.])
439
440
"""
441
from .polynomial import polyadd, polysub, polymulx
442
443
[c] = pu.as_series([c])
444
n = len(c)
445
if n < 3:
446
return c
447
else:
448
c0 = c[-2]
449
c1 = c[-1]
450
# i is the current degree of c1
451
for i in range(n - 1, 1, -1):
452
tmp = c0
453
c0 = polysub(c[i - 2], c1)
454
c1 = polyadd(tmp, polymulx(c1)*2)
455
return polyadd(c0, polymulx(c1))
456
457
458
#
459
# These are constant arrays are of integer type so as to be compatible
460
# with the widest range of other types, such as Decimal.
461
#
462
463
# Chebyshev default domain.
464
chebdomain = np.array([-1, 1])
465
466
# Chebyshev coefficients representing zero.
467
chebzero = np.array([0])
468
469
# Chebyshev coefficients representing one.
470
chebone = np.array([1])
471
472
# Chebyshev coefficients representing the identity x.
473
chebx = np.array([0, 1])
474
475
476
def chebline(off, scl):
477
"""
478
Chebyshev series whose graph is a straight line.
479
480
Parameters
481
----------
482
off, scl : scalars
483
The specified line is given by ``off + scl*x``.
484
485
Returns
486
-------
487
y : ndarray
488
This module's representation of the Chebyshev series for
489
``off + scl*x``.
490
491
See Also
492
--------
493
numpy.polynomial.polynomial.polyline
494
numpy.polynomial.legendre.legline
495
numpy.polynomial.laguerre.lagline
496
numpy.polynomial.hermite.hermline
497
numpy.polynomial.hermite_e.hermeline
498
499
Examples
500
--------
501
>>> import numpy.polynomial.chebyshev as C
502
>>> C.chebline(3,2)
503
array([3, 2])
504
>>> C.chebval(-3, C.chebline(3,2)) # should be -3
505
-3.0
506
507
"""
508
if scl != 0:
509
return np.array([off, scl])
510
else:
511
return np.array([off])
512
513
514
def chebfromroots(roots):
515
"""
516
Generate a Chebyshev series with given roots.
517
518
The function returns the coefficients of the polynomial
519
520
.. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n),
521
522
in Chebyshev form, where the `r_n` are the roots specified in `roots`.
523
If a zero has multiplicity n, then it must appear in `roots` n times.
524
For instance, if 2 is a root of multiplicity three and 3 is a root of
525
multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The
526
roots can appear in any order.
527
528
If the returned coefficients are `c`, then
529
530
.. math:: p(x) = c_0 + c_1 * T_1(x) + ... + c_n * T_n(x)
531
532
The coefficient of the last term is not generally 1 for monic
533
polynomials in Chebyshev form.
534
535
Parameters
536
----------
537
roots : array_like
538
Sequence containing the roots.
539
540
Returns
541
-------
542
out : ndarray
543
1-D array of coefficients. If all roots are real then `out` is a
544
real array, if some of the roots are complex, then `out` is complex
545
even if all the coefficients in the result are real (see Examples
546
below).
547
548
See Also
549
--------
550
numpy.polynomial.polynomial.polyfromroots
551
numpy.polynomial.legendre.legfromroots
552
numpy.polynomial.laguerre.lagfromroots
553
numpy.polynomial.hermite.hermfromroots
554
numpy.polynomial.hermite_e.hermefromroots
555
556
Examples
557
--------
558
>>> import numpy.polynomial.chebyshev as C
559
>>> C.chebfromroots((-1,0,1)) # x^3 - x relative to the standard basis
560
array([ 0. , -0.25, 0. , 0.25])
561
>>> j = complex(0,1)
562
>>> C.chebfromroots((-j,j)) # x^2 + 1 relative to the standard basis
563
array([1.5+0.j, 0. +0.j, 0.5+0.j])
564
565
"""
566
return pu._fromroots(chebline, chebmul, roots)
567
568
569
def chebadd(c1, c2):
570
"""
571
Add one Chebyshev series to another.
572
573
Returns the sum of two Chebyshev series `c1` + `c2`. The arguments
574
are sequences of coefficients ordered from lowest order term to
575
highest, i.e., [1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``.
576
577
Parameters
578
----------
579
c1, c2 : array_like
580
1-D arrays of Chebyshev series coefficients ordered from low to
581
high.
582
583
Returns
584
-------
585
out : ndarray
586
Array representing the Chebyshev series of their sum.
587
588
See Also
589
--------
590
chebsub, chebmulx, chebmul, chebdiv, chebpow
591
592
Notes
593
-----
594
Unlike multiplication, division, etc., the sum of two Chebyshev series
595
is a Chebyshev series (without having to "reproject" the result onto
596
the basis set) so addition, just like that of "standard" polynomials,
597
is simply "component-wise."
598
599
Examples
600
--------
601
>>> from numpy.polynomial import chebyshev as C
602
>>> c1 = (1,2,3)
603
>>> c2 = (3,2,1)
604
>>> C.chebadd(c1,c2)
605
array([4., 4., 4.])
606
607
"""
608
return pu._add(c1, c2)
609
610
611
def chebsub(c1, c2):
612
"""
613
Subtract one Chebyshev series from another.
614
615
Returns the difference of two Chebyshev series `c1` - `c2`. The
616
sequences of coefficients are from lowest order term to highest, i.e.,
617
[1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``.
618
619
Parameters
620
----------
621
c1, c2 : array_like
622
1-D arrays of Chebyshev series coefficients ordered from low to
623
high.
624
625
Returns
626
-------
627
out : ndarray
628
Of Chebyshev series coefficients representing their difference.
629
630
See Also
631
--------
632
chebadd, chebmulx, chebmul, chebdiv, chebpow
633
634
Notes
635
-----
636
Unlike multiplication, division, etc., the difference of two Chebyshev
637
series is a Chebyshev series (without having to "reproject" the result
638
onto the basis set) so subtraction, just like that of "standard"
639
polynomials, is simply "component-wise."
640
641
Examples
642
--------
643
>>> from numpy.polynomial import chebyshev as C
644
>>> c1 = (1,2,3)
645
>>> c2 = (3,2,1)
646
>>> C.chebsub(c1,c2)
647
array([-2., 0., 2.])
648
>>> C.chebsub(c2,c1) # -C.chebsub(c1,c2)
649
array([ 2., 0., -2.])
650
651
"""
652
return pu._sub(c1, c2)
653
654
655
def chebmulx(c):
656
"""Multiply a Chebyshev series by x.
657
658
Multiply the polynomial `c` by x, where x is the independent
659
variable.
660
661
662
Parameters
663
----------
664
c : array_like
665
1-D array of Chebyshev series coefficients ordered from low to
666
high.
667
668
Returns
669
-------
670
out : ndarray
671
Array representing the result of the multiplication.
672
673
Notes
674
-----
675
676
.. versionadded:: 1.5.0
677
678
Examples
679
--------
680
>>> from numpy.polynomial import chebyshev as C
681
>>> C.chebmulx([1,2,3])
682
array([1. , 2.5, 1. , 1.5])
683
684
"""
685
# c is a trimmed copy
686
[c] = pu.as_series([c])
687
# The zero series needs special treatment
688
if len(c) == 1 and c[0] == 0:
689
return c
690
691
prd = np.empty(len(c) + 1, dtype=c.dtype)
692
prd[0] = c[0]*0
693
prd[1] = c[0]
694
if len(c) > 1:
695
tmp = c[1:]/2
696
prd[2:] = tmp
697
prd[0:-2] += tmp
698
return prd
699
700
701
def chebmul(c1, c2):
702
"""
703
Multiply one Chebyshev series by another.
704
705
Returns the product of two Chebyshev series `c1` * `c2`. The arguments
706
are sequences of coefficients, from lowest order "term" to highest,
707
e.g., [1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``.
708
709
Parameters
710
----------
711
c1, c2 : array_like
712
1-D arrays of Chebyshev series coefficients ordered from low to
713
high.
714
715
Returns
716
-------
717
out : ndarray
718
Of Chebyshev series coefficients representing their product.
719
720
See Also
721
--------
722
chebadd, chebsub, chebmulx, chebdiv, chebpow
723
724
Notes
725
-----
726
In general, the (polynomial) product of two C-series results in terms
727
that are not in the Chebyshev polynomial basis set. Thus, to express
728
the product as a C-series, it is typically necessary to "reproject"
729
the product onto said basis set, which typically produces
730
"unintuitive live" (but correct) results; see Examples section below.
731
732
Examples
733
--------
734
>>> from numpy.polynomial import chebyshev as C
735
>>> c1 = (1,2,3)
736
>>> c2 = (3,2,1)
737
>>> C.chebmul(c1,c2) # multiplication requires "reprojection"
738
array([ 6.5, 12. , 12. , 4. , 1.5])
739
740
"""
741
# c1, c2 are trimmed copies
742
[c1, c2] = pu.as_series([c1, c2])
743
z1 = _cseries_to_zseries(c1)
744
z2 = _cseries_to_zseries(c2)
745
prd = _zseries_mul(z1, z2)
746
ret = _zseries_to_cseries(prd)
747
return pu.trimseq(ret)
748
749
750
def chebdiv(c1, c2):
751
"""
752
Divide one Chebyshev series by another.
753
754
Returns the quotient-with-remainder of two Chebyshev series
755
`c1` / `c2`. The arguments are sequences of coefficients from lowest
756
order "term" to highest, e.g., [1,2,3] represents the series
757
``T_0 + 2*T_1 + 3*T_2``.
758
759
Parameters
760
----------
761
c1, c2 : array_like
762
1-D arrays of Chebyshev series coefficients ordered from low to
763
high.
764
765
Returns
766
-------
767
[quo, rem] : ndarrays
768
Of Chebyshev series coefficients representing the quotient and
769
remainder.
770
771
See Also
772
--------
773
chebadd, chebsub, chebmulx, chebmul, chebpow
774
775
Notes
776
-----
777
In general, the (polynomial) division of one C-series by another
778
results in quotient and remainder terms that are not in the Chebyshev
779
polynomial basis set. Thus, to express these results as C-series, it
780
is typically necessary to "reproject" the results onto said basis
781
set, which typically produces "unintuitive" (but correct) results;
782
see Examples section below.
783
784
Examples
785
--------
786
>>> from numpy.polynomial import chebyshev as C
787
>>> c1 = (1,2,3)
788
>>> c2 = (3,2,1)
789
>>> C.chebdiv(c1,c2) # quotient "intuitive," remainder not
790
(array([3.]), array([-8., -4.]))
791
>>> c2 = (0,1,2,3)
792
>>> C.chebdiv(c2,c1) # neither "intuitive"
793
(array([0., 2.]), array([-2., -4.]))
794
795
"""
796
# c1, c2 are trimmed copies
797
[c1, c2] = pu.as_series([c1, c2])
798
if c2[-1] == 0:
799
raise ZeroDivisionError()
800
801
# note: this is more efficient than `pu._div(chebmul, c1, c2)`
802
lc1 = len(c1)
803
lc2 = len(c2)
804
if lc1 < lc2:
805
return c1[:1]*0, c1
806
elif lc2 == 1:
807
return c1/c2[-1], c1[:1]*0
808
else:
809
z1 = _cseries_to_zseries(c1)
810
z2 = _cseries_to_zseries(c2)
811
quo, rem = _zseries_div(z1, z2)
812
quo = pu.trimseq(_zseries_to_cseries(quo))
813
rem = pu.trimseq(_zseries_to_cseries(rem))
814
return quo, rem
815
816
817
def chebpow(c, pow, maxpower=16):
818
"""Raise a Chebyshev series to a power.
819
820
Returns the Chebyshev series `c` raised to the power `pow`. The
821
argument `c` is a sequence of coefficients ordered from low to high.
822
i.e., [1,2,3] is the series ``T_0 + 2*T_1 + 3*T_2.``
823
824
Parameters
825
----------
826
c : array_like
827
1-D array of Chebyshev series coefficients ordered from low to
828
high.
829
pow : integer
830
Power to which the series will be raised
831
maxpower : integer, optional
832
Maximum power allowed. This is mainly to limit growth of the series
833
to unmanageable size. Default is 16
834
835
Returns
836
-------
837
coef : ndarray
838
Chebyshev series of power.
839
840
See Also
841
--------
842
chebadd, chebsub, chebmulx, chebmul, chebdiv
843
844
Examples
845
--------
846
>>> from numpy.polynomial import chebyshev as C
847
>>> C.chebpow([1, 2, 3, 4], 2)
848
array([15.5, 22. , 16. , ..., 12.5, 12. , 8. ])
849
850
"""
851
# note: this is more efficient than `pu._pow(chebmul, c1, c2)`, as it
852
# avoids converting between z and c series repeatedly
853
854
# c is a trimmed copy
855
[c] = pu.as_series([c])
856
power = int(pow)
857
if power != pow or power < 0:
858
raise ValueError("Power must be a non-negative integer.")
859
elif maxpower is not None and power > maxpower:
860
raise ValueError("Power is too large")
861
elif power == 0:
862
return np.array([1], dtype=c.dtype)
863
elif power == 1:
864
return c
865
else:
866
# This can be made more efficient by using powers of two
867
# in the usual way.
868
zs = _cseries_to_zseries(c)
869
prd = zs
870
for i in range(2, power + 1):
871
prd = np.convolve(prd, zs)
872
return _zseries_to_cseries(prd)
873
874
875
def chebder(c, m=1, scl=1, axis=0):
876
"""
877
Differentiate a Chebyshev series.
878
879
Returns the Chebyshev series coefficients `c` differentiated `m` times
880
along `axis`. At each iteration the result is multiplied by `scl` (the
881
scaling factor is for use in a linear change of variable). The argument
882
`c` is an array of coefficients from low to high degree along each
883
axis, e.g., [1,2,3] represents the series ``1*T_0 + 2*T_1 + 3*T_2``
884
while [[1,2],[1,2]] represents ``1*T_0(x)*T_0(y) + 1*T_1(x)*T_0(y) +
885
2*T_0(x)*T_1(y) + 2*T_1(x)*T_1(y)`` if axis=0 is ``x`` and axis=1 is
886
``y``.
887
888
Parameters
889
----------
890
c : array_like
891
Array of Chebyshev series coefficients. If c is multidimensional
892
the different axis correspond to different variables with the
893
degree in each axis given by the corresponding index.
894
m : int, optional
895
Number of derivatives taken, must be non-negative. (Default: 1)
896
scl : scalar, optional
897
Each differentiation is multiplied by `scl`. The end result is
898
multiplication by ``scl**m``. This is for use in a linear change of
899
variable. (Default: 1)
900
axis : int, optional
901
Axis over which the derivative is taken. (Default: 0).
902
903
.. versionadded:: 1.7.0
904
905
Returns
906
-------
907
der : ndarray
908
Chebyshev series of the derivative.
909
910
See Also
911
--------
912
chebint
913
914
Notes
915
-----
916
In general, the result of differentiating a C-series needs to be
917
"reprojected" onto the C-series basis set. Thus, typically, the
918
result of this function is "unintuitive," albeit correct; see Examples
919
section below.
920
921
Examples
922
--------
923
>>> from numpy.polynomial import chebyshev as C
924
>>> c = (1,2,3,4)
925
>>> C.chebder(c)
926
array([14., 12., 24.])
927
>>> C.chebder(c,3)
928
array([96.])
929
>>> C.chebder(c,scl=-1)
930
array([-14., -12., -24.])
931
>>> C.chebder(c,2,-1)
932
array([12., 96.])
933
934
"""
935
c = np.array(c, ndmin=1, copy=True)
936
if c.dtype.char in '?bBhHiIlLqQpP':
937
c = c.astype(np.double)
938
cnt = pu._deprecate_as_int(m, "the order of derivation")
939
iaxis = pu._deprecate_as_int(axis, "the axis")
940
if cnt < 0:
941
raise ValueError("The order of derivation must be non-negative")
942
iaxis = normalize_axis_index(iaxis, c.ndim)
943
944
if cnt == 0:
945
return c
946
947
c = np.moveaxis(c, iaxis, 0)
948
n = len(c)
949
if cnt >= n:
950
c = c[:1]*0
951
else:
952
for i in range(cnt):
953
n = n - 1
954
c *= scl
955
der = np.empty((n,) + c.shape[1:], dtype=c.dtype)
956
for j in range(n, 2, -1):
957
der[j - 1] = (2*j)*c[j]
958
c[j - 2] += (j*c[j])/(j - 2)
959
if n > 1:
960
der[1] = 4*c[2]
961
der[0] = c[1]
962
c = der
963
c = np.moveaxis(c, 0, iaxis)
964
return c
965
966
967
def chebint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
968
"""
969
Integrate a Chebyshev series.
970
971
Returns the Chebyshev series coefficients `c` integrated `m` times from
972
`lbnd` along `axis`. At each iteration the resulting series is
973
**multiplied** by `scl` and an integration constant, `k`, is added.
974
The scaling factor is for use in a linear change of variable. ("Buyer
975
beware": note that, depending on what one is doing, one may want `scl`
976
to be the reciprocal of what one might expect; for more information,
977
see the Notes section below.) The argument `c` is an array of
978
coefficients from low to high degree along each axis, e.g., [1,2,3]
979
represents the series ``T_0 + 2*T_1 + 3*T_2`` while [[1,2],[1,2]]
980
represents ``1*T_0(x)*T_0(y) + 1*T_1(x)*T_0(y) + 2*T_0(x)*T_1(y) +
981
2*T_1(x)*T_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.
982
983
Parameters
984
----------
985
c : array_like
986
Array of Chebyshev series coefficients. If c is multidimensional
987
the different axis correspond to different variables with the
988
degree in each axis given by the corresponding index.
989
m : int, optional
990
Order of integration, must be positive. (Default: 1)
991
k : {[], list, scalar}, optional
992
Integration constant(s). The value of the first integral at zero
993
is the first value in the list, the value of the second integral
994
at zero is the second value, etc. If ``k == []`` (the default),
995
all constants are set to zero. If ``m == 1``, a single scalar can
996
be given instead of a list.
997
lbnd : scalar, optional
998
The lower bound of the integral. (Default: 0)
999
scl : scalar, optional
1000
Following each integration the result is *multiplied* by `scl`
1001
before the integration constant is added. (Default: 1)
1002
axis : int, optional
1003
Axis over which the integral is taken. (Default: 0).
1004
1005
.. versionadded:: 1.7.0
1006
1007
Returns
1008
-------
1009
S : ndarray
1010
C-series coefficients of the integral.
1011
1012
Raises
1013
------
1014
ValueError
1015
If ``m < 1``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or
1016
``np.ndim(scl) != 0``.
1017
1018
See Also
1019
--------
1020
chebder
1021
1022
Notes
1023
-----
1024
Note that the result of each integration is *multiplied* by `scl`.
1025
Why is this important to note? Say one is making a linear change of
1026
variable :math:`u = ax + b` in an integral relative to `x`. Then
1027
:math:`dx = du/a`, so one will need to set `scl` equal to
1028
:math:`1/a`- perhaps not what one would have first thought.
1029
1030
Also note that, in general, the result of integrating a C-series needs
1031
to be "reprojected" onto the C-series basis set. Thus, typically,
1032
the result of this function is "unintuitive," albeit correct; see
1033
Examples section below.
1034
1035
Examples
1036
--------
1037
>>> from numpy.polynomial import chebyshev as C
1038
>>> c = (1,2,3)
1039
>>> C.chebint(c)
1040
array([ 0.5, -0.5, 0.5, 0.5])
1041
>>> C.chebint(c,3)
1042
array([ 0.03125 , -0.1875 , 0.04166667, -0.05208333, 0.01041667, # may vary
1043
0.00625 ])
1044
>>> C.chebint(c, k=3)
1045
array([ 3.5, -0.5, 0.5, 0.5])
1046
>>> C.chebint(c,lbnd=-2)
1047
array([ 8.5, -0.5, 0.5, 0.5])
1048
>>> C.chebint(c,scl=-2)
1049
array([-1., 1., -1., -1.])
1050
1051
"""
1052
c = np.array(c, ndmin=1, copy=True)
1053
if c.dtype.char in '?bBhHiIlLqQpP':
1054
c = c.astype(np.double)
1055
if not np.iterable(k):
1056
k = [k]
1057
cnt = pu._deprecate_as_int(m, "the order of integration")
1058
iaxis = pu._deprecate_as_int(axis, "the axis")
1059
if cnt < 0:
1060
raise ValueError("The order of integration must be non-negative")
1061
if len(k) > cnt:
1062
raise ValueError("Too many integration constants")
1063
if np.ndim(lbnd) != 0:
1064
raise ValueError("lbnd must be a scalar.")
1065
if np.ndim(scl) != 0:
1066
raise ValueError("scl must be a scalar.")
1067
iaxis = normalize_axis_index(iaxis, c.ndim)
1068
1069
if cnt == 0:
1070
return c
1071
1072
c = np.moveaxis(c, iaxis, 0)
1073
k = list(k) + [0]*(cnt - len(k))
1074
for i in range(cnt):
1075
n = len(c)
1076
c *= scl
1077
if n == 1 and np.all(c[0] == 0):
1078
c[0] += k[i]
1079
else:
1080
tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)
1081
tmp[0] = c[0]*0
1082
tmp[1] = c[0]
1083
if n > 1:
1084
tmp[2] = c[1]/4
1085
for j in range(2, n):
1086
tmp[j + 1] = c[j]/(2*(j + 1))
1087
tmp[j - 1] -= c[j]/(2*(j - 1))
1088
tmp[0] += k[i] - chebval(lbnd, tmp)
1089
c = tmp
1090
c = np.moveaxis(c, 0, iaxis)
1091
return c
1092
1093
1094
def chebval(x, c, tensor=True):
1095
"""
1096
Evaluate a Chebyshev series at points x.
1097
1098
If `c` is of length `n + 1`, this function returns the value:
1099
1100
.. math:: p(x) = c_0 * T_0(x) + c_1 * T_1(x) + ... + c_n * T_n(x)
1101
1102
The parameter `x` is converted to an array only if it is a tuple or a
1103
list, otherwise it is treated as a scalar. In either case, either `x`
1104
or its elements must support multiplication and addition both with
1105
themselves and with the elements of `c`.
1106
1107
If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If
1108
`c` is multidimensional, then the shape of the result depends on the
1109
value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +
1110
x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that
1111
scalars have shape (,).
1112
1113
Trailing zeros in the coefficients will be used in the evaluation, so
1114
they should be avoided if efficiency is a concern.
1115
1116
Parameters
1117
----------
1118
x : array_like, compatible object
1119
If `x` is a list or tuple, it is converted to an ndarray, otherwise
1120
it is left unchanged and treated as a scalar. In either case, `x`
1121
or its elements must support addition and multiplication with
1122
with themselves and with the elements of `c`.
1123
c : array_like
1124
Array of coefficients ordered so that the coefficients for terms of
1125
degree n are contained in c[n]. If `c` is multidimensional the
1126
remaining indices enumerate multiple polynomials. In the two
1127
dimensional case the coefficients may be thought of as stored in
1128
the columns of `c`.
1129
tensor : boolean, optional
1130
If True, the shape of the coefficient array is extended with ones
1131
on the right, one for each dimension of `x`. Scalars have dimension 0
1132
for this action. The result is that every column of coefficients in
1133
`c` is evaluated for every element of `x`. If False, `x` is broadcast
1134
over the columns of `c` for the evaluation. This keyword is useful
1135
when `c` is multidimensional. The default value is True.
1136
1137
.. versionadded:: 1.7.0
1138
1139
Returns
1140
-------
1141
values : ndarray, algebra_like
1142
The shape of the return value is described above.
1143
1144
See Also
1145
--------
1146
chebval2d, chebgrid2d, chebval3d, chebgrid3d
1147
1148
Notes
1149
-----
1150
The evaluation uses Clenshaw recursion, aka synthetic division.
1151
1152
"""
1153
c = np.array(c, ndmin=1, copy=True)
1154
if c.dtype.char in '?bBhHiIlLqQpP':
1155
c = c.astype(np.double)
1156
if isinstance(x, (tuple, list)):
1157
x = np.asarray(x)
1158
if isinstance(x, np.ndarray) and tensor:
1159
c = c.reshape(c.shape + (1,)*x.ndim)
1160
1161
if len(c) == 1:
1162
c0 = c[0]
1163
c1 = 0
1164
elif len(c) == 2:
1165
c0 = c[0]
1166
c1 = c[1]
1167
else:
1168
x2 = 2*x
1169
c0 = c[-2]
1170
c1 = c[-1]
1171
for i in range(3, len(c) + 1):
1172
tmp = c0
1173
c0 = c[-i] - c1
1174
c1 = tmp + c1*x2
1175
return c0 + c1*x
1176
1177
1178
def chebval2d(x, y, c):
1179
"""
1180
Evaluate a 2-D Chebyshev series at points (x, y).
1181
1182
This function returns the values:
1183
1184
.. math:: p(x,y) = \\sum_{i,j} c_{i,j} * T_i(x) * T_j(y)
1185
1186
The parameters `x` and `y` are converted to arrays only if they are
1187
tuples or a lists, otherwise they are treated as a scalars and they
1188
must have the same shape after conversion. In either case, either `x`
1189
and `y` or their elements must support multiplication and addition both
1190
with themselves and with the elements of `c`.
1191
1192
If `c` is a 1-D array a one is implicitly appended to its shape to make
1193
it 2-D. The shape of the result will be c.shape[2:] + x.shape.
1194
1195
Parameters
1196
----------
1197
x, y : array_like, compatible objects
1198
The two dimensional series is evaluated at the points `(x, y)`,
1199
where `x` and `y` must have the same shape. If `x` or `y` is a list
1200
or tuple, it is first converted to an ndarray, otherwise it is left
1201
unchanged and if it isn't an ndarray it is treated as a scalar.
1202
c : array_like
1203
Array of coefficients ordered so that the coefficient of the term
1204
of multi-degree i,j is contained in ``c[i,j]``. If `c` has
1205
dimension greater than 2 the remaining indices enumerate multiple
1206
sets of coefficients.
1207
1208
Returns
1209
-------
1210
values : ndarray, compatible object
1211
The values of the two dimensional Chebyshev series at points formed
1212
from pairs of corresponding values from `x` and `y`.
1213
1214
See Also
1215
--------
1216
chebval, chebgrid2d, chebval3d, chebgrid3d
1217
1218
Notes
1219
-----
1220
1221
.. versionadded:: 1.7.0
1222
1223
"""
1224
return pu._valnd(chebval, c, x, y)
1225
1226
1227
def chebgrid2d(x, y, c):
1228
"""
1229
Evaluate a 2-D Chebyshev series on the Cartesian product of x and y.
1230
1231
This function returns the values:
1232
1233
.. math:: p(a,b) = \\sum_{i,j} c_{i,j} * T_i(a) * T_j(b),
1234
1235
where the points `(a, b)` consist of all pairs formed by taking
1236
`a` from `x` and `b` from `y`. The resulting points form a grid with
1237
`x` in the first dimension and `y` in the second.
1238
1239
The parameters `x` and `y` are converted to arrays only if they are
1240
tuples or a lists, otherwise they are treated as a scalars. In either
1241
case, either `x` and `y` or their elements must support multiplication
1242
and addition both with themselves and with the elements of `c`.
1243
1244
If `c` has fewer than two dimensions, ones are implicitly appended to
1245
its shape to make it 2-D. The shape of the result will be c.shape[2:] +
1246
x.shape + y.shape.
1247
1248
Parameters
1249
----------
1250
x, y : array_like, compatible objects
1251
The two dimensional series is evaluated at the points in the
1252
Cartesian product of `x` and `y`. If `x` or `y` is a list or
1253
tuple, it is first converted to an ndarray, otherwise it is left
1254
unchanged and, if it isn't an ndarray, it is treated as a scalar.
1255
c : array_like
1256
Array of coefficients ordered so that the coefficient of the term of
1257
multi-degree i,j is contained in `c[i,j]`. If `c` has dimension
1258
greater than two the remaining indices enumerate multiple sets of
1259
coefficients.
1260
1261
Returns
1262
-------
1263
values : ndarray, compatible object
1264
The values of the two dimensional Chebyshev series at points in the
1265
Cartesian product of `x` and `y`.
1266
1267
See Also
1268
--------
1269
chebval, chebval2d, chebval3d, chebgrid3d
1270
1271
Notes
1272
-----
1273
1274
.. versionadded:: 1.7.0
1275
1276
"""
1277
return pu._gridnd(chebval, c, x, y)
1278
1279
1280
def chebval3d(x, y, z, c):
1281
"""
1282
Evaluate a 3-D Chebyshev series at points (x, y, z).
1283
1284
This function returns the values:
1285
1286
.. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * T_i(x) * T_j(y) * T_k(z)
1287
1288
The parameters `x`, `y`, and `z` are converted to arrays only if
1289
they are tuples or a lists, otherwise they are treated as a scalars and
1290
they must have the same shape after conversion. In either case, either
1291
`x`, `y`, and `z` or their elements must support multiplication and
1292
addition both with themselves and with the elements of `c`.
1293
1294
If `c` has fewer than 3 dimensions, ones are implicitly appended to its
1295
shape to make it 3-D. The shape of the result will be c.shape[3:] +
1296
x.shape.
1297
1298
Parameters
1299
----------
1300
x, y, z : array_like, compatible object
1301
The three dimensional series is evaluated at the points
1302
`(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If
1303
any of `x`, `y`, or `z` is a list or tuple, it is first converted
1304
to an ndarray, otherwise it is left unchanged and if it isn't an
1305
ndarray it is treated as a scalar.
1306
c : array_like
1307
Array of coefficients ordered so that the coefficient of the term of
1308
multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension
1309
greater than 3 the remaining indices enumerate multiple sets of
1310
coefficients.
1311
1312
Returns
1313
-------
1314
values : ndarray, compatible object
1315
The values of the multidimensional polynomial on points formed with
1316
triples of corresponding values from `x`, `y`, and `z`.
1317
1318
See Also
1319
--------
1320
chebval, chebval2d, chebgrid2d, chebgrid3d
1321
1322
Notes
1323
-----
1324
1325
.. versionadded:: 1.7.0
1326
1327
"""
1328
return pu._valnd(chebval, c, x, y, z)
1329
1330
1331
def chebgrid3d(x, y, z, c):
1332
"""
1333
Evaluate a 3-D Chebyshev series on the Cartesian product of x, y, and z.
1334
1335
This function returns the values:
1336
1337
.. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * T_i(a) * T_j(b) * T_k(c)
1338
1339
where the points `(a, b, c)` consist of all triples formed by taking
1340
`a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form
1341
a grid with `x` in the first dimension, `y` in the second, and `z` in
1342
the third.
1343
1344
The parameters `x`, `y`, and `z` are converted to arrays only if they
1345
are tuples or a lists, otherwise they are treated as a scalars. In
1346
either case, either `x`, `y`, and `z` or their elements must support
1347
multiplication and addition both with themselves and with the elements
1348
of `c`.
1349
1350
If `c` has fewer than three dimensions, ones are implicitly appended to
1351
its shape to make it 3-D. The shape of the result will be c.shape[3:] +
1352
x.shape + y.shape + z.shape.
1353
1354
Parameters
1355
----------
1356
x, y, z : array_like, compatible objects
1357
The three dimensional series is evaluated at the points in the
1358
Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a
1359
list or tuple, it is first converted to an ndarray, otherwise it is
1360
left unchanged and, if it isn't an ndarray, it is treated as a
1361
scalar.
1362
c : array_like
1363
Array of coefficients ordered so that the coefficients for terms of
1364
degree i,j are contained in ``c[i,j]``. If `c` has dimension
1365
greater than two the remaining indices enumerate multiple sets of
1366
coefficients.
1367
1368
Returns
1369
-------
1370
values : ndarray, compatible object
1371
The values of the two dimensional polynomial at points in the Cartesian
1372
product of `x` and `y`.
1373
1374
See Also
1375
--------
1376
chebval, chebval2d, chebgrid2d, chebval3d
1377
1378
Notes
1379
-----
1380
1381
.. versionadded:: 1.7.0
1382
1383
"""
1384
return pu._gridnd(chebval, c, x, y, z)
1385
1386
1387
def chebvander(x, deg):
1388
"""Pseudo-Vandermonde matrix of given degree.
1389
1390
Returns the pseudo-Vandermonde matrix of degree `deg` and sample points
1391
`x`. The pseudo-Vandermonde matrix is defined by
1392
1393
.. math:: V[..., i] = T_i(x),
1394
1395
where `0 <= i <= deg`. The leading indices of `V` index the elements of
1396
`x` and the last index is the degree of the Chebyshev polynomial.
1397
1398
If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the
1399
matrix ``V = chebvander(x, n)``, then ``np.dot(V, c)`` and
1400
``chebval(x, c)`` are the same up to roundoff. This equivalence is
1401
useful both for least squares fitting and for the evaluation of a large
1402
number of Chebyshev series of the same degree and sample points.
1403
1404
Parameters
1405
----------
1406
x : array_like
1407
Array of points. The dtype is converted to float64 or complex128
1408
depending on whether any of the elements are complex. If `x` is
1409
scalar it is converted to a 1-D array.
1410
deg : int
1411
Degree of the resulting matrix.
1412
1413
Returns
1414
-------
1415
vander : ndarray
1416
The pseudo Vandermonde matrix. The shape of the returned matrix is
1417
``x.shape + (deg + 1,)``, where The last index is the degree of the
1418
corresponding Chebyshev polynomial. The dtype will be the same as
1419
the converted `x`.
1420
1421
"""
1422
ideg = pu._deprecate_as_int(deg, "deg")
1423
if ideg < 0:
1424
raise ValueError("deg must be non-negative")
1425
1426
x = np.array(x, copy=False, ndmin=1) + 0.0
1427
dims = (ideg + 1,) + x.shape
1428
dtyp = x.dtype
1429
v = np.empty(dims, dtype=dtyp)
1430
# Use forward recursion to generate the entries.
1431
v[0] = x*0 + 1
1432
if ideg > 0:
1433
x2 = 2*x
1434
v[1] = x
1435
for i in range(2, ideg + 1):
1436
v[i] = v[i-1]*x2 - v[i-2]
1437
return np.moveaxis(v, 0, -1)
1438
1439
1440
def chebvander2d(x, y, deg):
1441
"""Pseudo-Vandermonde matrix of given degrees.
1442
1443
Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
1444
points `(x, y)`. The pseudo-Vandermonde matrix is defined by
1445
1446
.. math:: V[..., (deg[1] + 1)*i + j] = T_i(x) * T_j(y),
1447
1448
where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of
1449
`V` index the points `(x, y)` and the last index encodes the degrees of
1450
the Chebyshev polynomials.
1451
1452
If ``V = chebvander2d(x, y, [xdeg, ydeg])``, then the columns of `V`
1453
correspond to the elements of a 2-D coefficient array `c` of shape
1454
(xdeg + 1, ydeg + 1) in the order
1455
1456
.. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ...
1457
1458
and ``np.dot(V, c.flat)`` and ``chebval2d(x, y, c)`` will be the same
1459
up to roundoff. This equivalence is useful both for least squares
1460
fitting and for the evaluation of a large number of 2-D Chebyshev
1461
series of the same degrees and sample points.
1462
1463
Parameters
1464
----------
1465
x, y : array_like
1466
Arrays of point coordinates, all of the same shape. The dtypes
1467
will be converted to either float64 or complex128 depending on
1468
whether any of the elements are complex. Scalars are converted to
1469
1-D arrays.
1470
deg : list of ints
1471
List of maximum degrees of the form [x_deg, y_deg].
1472
1473
Returns
1474
-------
1475
vander2d : ndarray
1476
The shape of the returned matrix is ``x.shape + (order,)``, where
1477
:math:`order = (deg[0]+1)*(deg[1]+1)`. The dtype will be the same
1478
as the converted `x` and `y`.
1479
1480
See Also
1481
--------
1482
chebvander, chebvander3d, chebval2d, chebval3d
1483
1484
Notes
1485
-----
1486
1487
.. versionadded:: 1.7.0
1488
1489
"""
1490
return pu._vander_nd_flat((chebvander, chebvander), (x, y), deg)
1491
1492
1493
def chebvander3d(x, y, z, deg):
1494
"""Pseudo-Vandermonde matrix of given degrees.
1495
1496
Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
1497
points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`,
1498
then The pseudo-Vandermonde matrix is defined by
1499
1500
.. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = T_i(x)*T_j(y)*T_k(z),
1501
1502
where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading
1503
indices of `V` index the points `(x, y, z)` and the last index encodes
1504
the degrees of the Chebyshev polynomials.
1505
1506
If ``V = chebvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns
1507
of `V` correspond to the elements of a 3-D coefficient array `c` of
1508
shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order
1509
1510
.. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...
1511
1512
and ``np.dot(V, c.flat)`` and ``chebval3d(x, y, z, c)`` will be the
1513
same up to roundoff. This equivalence is useful both for least squares
1514
fitting and for the evaluation of a large number of 3-D Chebyshev
1515
series of the same degrees and sample points.
1516
1517
Parameters
1518
----------
1519
x, y, z : array_like
1520
Arrays of point coordinates, all of the same shape. The dtypes will
1521
be converted to either float64 or complex128 depending on whether
1522
any of the elements are complex. Scalars are converted to 1-D
1523
arrays.
1524
deg : list of ints
1525
List of maximum degrees of the form [x_deg, y_deg, z_deg].
1526
1527
Returns
1528
-------
1529
vander3d : ndarray
1530
The shape of the returned matrix is ``x.shape + (order,)``, where
1531
:math:`order = (deg[0]+1)*(deg[1]+1)*(deg[2]+1)`. The dtype will
1532
be the same as the converted `x`, `y`, and `z`.
1533
1534
See Also
1535
--------
1536
chebvander, chebvander3d, chebval2d, chebval3d
1537
1538
Notes
1539
-----
1540
1541
.. versionadded:: 1.7.0
1542
1543
"""
1544
return pu._vander_nd_flat((chebvander, chebvander, chebvander), (x, y, z), deg)
1545
1546
1547
def chebfit(x, y, deg, rcond=None, full=False, w=None):
1548
"""
1549
Least squares fit of Chebyshev series to data.
1550
1551
Return the coefficients of a Chebyshev series of degree `deg` that is the
1552
least squares fit to the data values `y` given at points `x`. If `y` is
1553
1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple
1554
fits are done, one for each column of `y`, and the resulting
1555
coefficients are stored in the corresponding columns of a 2-D return.
1556
The fitted polynomial(s) are in the form
1557
1558
.. math:: p(x) = c_0 + c_1 * T_1(x) + ... + c_n * T_n(x),
1559
1560
where `n` is `deg`.
1561
1562
Parameters
1563
----------
1564
x : array_like, shape (M,)
1565
x-coordinates of the M sample points ``(x[i], y[i])``.
1566
y : array_like, shape (M,) or (M, K)
1567
y-coordinates of the sample points. Several data sets of sample
1568
points sharing the same x-coordinates can be fitted at once by
1569
passing in a 2D-array that contains one dataset per column.
1570
deg : int or 1-D array_like
1571
Degree(s) of the fitting polynomials. If `deg` is a single integer,
1572
all terms up to and including the `deg`'th term are included in the
1573
fit. For NumPy versions >= 1.11.0 a list of integers specifying the
1574
degrees of the terms to include may be used instead.
1575
rcond : float, optional
1576
Relative condition number of the fit. Singular values smaller than
1577
this relative to the largest singular value will be ignored. The
1578
default value is len(x)*eps, where eps is the relative precision of
1579
the float type, about 2e-16 in most cases.
1580
full : bool, optional
1581
Switch determining nature of return value. When it is False (the
1582
default) just the coefficients are returned, when True diagnostic
1583
information from the singular value decomposition is also returned.
1584
w : array_like, shape (`M`,), optional
1585
Weights. If not None, the weight ``w[i]`` applies to the unsquared
1586
residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are
1587
chosen so that the errors of the products ``w[i]*y[i]`` all have the
1588
same variance. When using inverse-variance weighting, use
1589
``w[i] = 1/sigma(y[i])``. The default value is None.
1590
1591
.. versionadded:: 1.5.0
1592
1593
Returns
1594
-------
1595
coef : ndarray, shape (M,) or (M, K)
1596
Chebyshev coefficients ordered from low to high. If `y` was 2-D,
1597
the coefficients for the data in column k of `y` are in column
1598
`k`.
1599
1600
[residuals, rank, singular_values, rcond] : list
1601
These values are only returned if ``full == True``
1602
1603
- residuals -- sum of squared residuals of the least squares fit
1604
- rank -- the numerical rank of the scaled Vandermonde matrix
1605
- singular_values -- singular values of the scaled Vandermonde matrix
1606
- rcond -- value of `rcond`.
1607
1608
For more details, see `numpy.linalg.lstsq`.
1609
1610
Warns
1611
-----
1612
RankWarning
1613
The rank of the coefficient matrix in the least-squares fit is
1614
deficient. The warning is only raised if ``full == False``. The
1615
warnings can be turned off by
1616
1617
>>> import warnings
1618
>>> warnings.simplefilter('ignore', np.RankWarning)
1619
1620
See Also
1621
--------
1622
numpy.polynomial.polynomial.polyfit
1623
numpy.polynomial.legendre.legfit
1624
numpy.polynomial.laguerre.lagfit
1625
numpy.polynomial.hermite.hermfit
1626
numpy.polynomial.hermite_e.hermefit
1627
chebval : Evaluates a Chebyshev series.
1628
chebvander : Vandermonde matrix of Chebyshev series.
1629
chebweight : Chebyshev weight function.
1630
numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
1631
scipy.interpolate.UnivariateSpline : Computes spline fits.
1632
1633
Notes
1634
-----
1635
The solution is the coefficients of the Chebyshev series `p` that
1636
minimizes the sum of the weighted squared errors
1637
1638
.. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,
1639
1640
where :math:`w_j` are the weights. This problem is solved by setting up
1641
as the (typically) overdetermined matrix equation
1642
1643
.. math:: V(x) * c = w * y,
1644
1645
where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the
1646
coefficients to be solved for, `w` are the weights, and `y` are the
1647
observed values. This equation is then solved using the singular value
1648
decomposition of `V`.
1649
1650
If some of the singular values of `V` are so small that they are
1651
neglected, then a `RankWarning` will be issued. This means that the
1652
coefficient values may be poorly determined. Using a lower order fit
1653
will usually get rid of the warning. The `rcond` parameter can also be
1654
set to a value smaller than its default, but the resulting fit may be
1655
spurious and have large contributions from roundoff error.
1656
1657
Fits using Chebyshev series are usually better conditioned than fits
1658
using power series, but much can depend on the distribution of the
1659
sample points and the smoothness of the data. If the quality of the fit
1660
is inadequate splines may be a good alternative.
1661
1662
References
1663
----------
1664
.. [1] Wikipedia, "Curve fitting",
1665
https://en.wikipedia.org/wiki/Curve_fitting
1666
1667
Examples
1668
--------
1669
1670
"""
1671
return pu._fit(chebvander, x, y, deg, rcond, full, w)
1672
1673
1674
def chebcompanion(c):
1675
"""Return the scaled companion matrix of c.
1676
1677
The basis polynomials are scaled so that the companion matrix is
1678
symmetric when `c` is a Chebyshev basis polynomial. This provides
1679
better eigenvalue estimates than the unscaled case and for basis
1680
polynomials the eigenvalues are guaranteed to be real if
1681
`numpy.linalg.eigvalsh` is used to obtain them.
1682
1683
Parameters
1684
----------
1685
c : array_like
1686
1-D array of Chebyshev series coefficients ordered from low to high
1687
degree.
1688
1689
Returns
1690
-------
1691
mat : ndarray
1692
Scaled companion matrix of dimensions (deg, deg).
1693
1694
Notes
1695
-----
1696
1697
.. versionadded:: 1.7.0
1698
1699
"""
1700
# c is a trimmed copy
1701
[c] = pu.as_series([c])
1702
if len(c) < 2:
1703
raise ValueError('Series must have maximum degree of at least 1.')
1704
if len(c) == 2:
1705
return np.array([[-c[0]/c[1]]])
1706
1707
n = len(c) - 1
1708
mat = np.zeros((n, n), dtype=c.dtype)
1709
scl = np.array([1.] + [np.sqrt(.5)]*(n-1))
1710
top = mat.reshape(-1)[1::n+1]
1711
bot = mat.reshape(-1)[n::n+1]
1712
top[0] = np.sqrt(.5)
1713
top[1:] = 1/2
1714
bot[...] = top
1715
mat[:, -1] -= (c[:-1]/c[-1])*(scl/scl[-1])*.5
1716
return mat
1717
1718
1719
def chebroots(c):
1720
"""
1721
Compute the roots of a Chebyshev series.
1722
1723
Return the roots (a.k.a. "zeros") of the polynomial
1724
1725
.. math:: p(x) = \\sum_i c[i] * T_i(x).
1726
1727
Parameters
1728
----------
1729
c : 1-D array_like
1730
1-D array of coefficients.
1731
1732
Returns
1733
-------
1734
out : ndarray
1735
Array of the roots of the series. If all the roots are real,
1736
then `out` is also real, otherwise it is complex.
1737
1738
See Also
1739
--------
1740
numpy.polynomial.polynomial.polyroots
1741
numpy.polynomial.legendre.legroots
1742
numpy.polynomial.laguerre.lagroots
1743
numpy.polynomial.hermite.hermroots
1744
numpy.polynomial.hermite_e.hermeroots
1745
1746
Notes
1747
-----
1748
The root estimates are obtained as the eigenvalues of the companion
1749
matrix, Roots far from the origin of the complex plane may have large
1750
errors due to the numerical instability of the series for such
1751
values. Roots with multiplicity greater than 1 will also show larger
1752
errors as the value of the series near such points is relatively
1753
insensitive to errors in the roots. Isolated roots near the origin can
1754
be improved by a few iterations of Newton's method.
1755
1756
The Chebyshev series basis polynomials aren't powers of `x` so the
1757
results of this function may seem unintuitive.
1758
1759
Examples
1760
--------
1761
>>> import numpy.polynomial.chebyshev as cheb
1762
>>> cheb.chebroots((-1, 1,-1, 1)) # T3 - T2 + T1 - T0 has real roots
1763
array([ -5.00000000e-01, 2.60860684e-17, 1.00000000e+00]) # may vary
1764
1765
"""
1766
# c is a trimmed copy
1767
[c] = pu.as_series([c])
1768
if len(c) < 2:
1769
return np.array([], dtype=c.dtype)
1770
if len(c) == 2:
1771
return np.array([-c[0]/c[1]])
1772
1773
# rotated companion matrix reduces error
1774
m = chebcompanion(c)[::-1,::-1]
1775
r = la.eigvals(m)
1776
r.sort()
1777
return r
1778
1779
1780
def chebinterpolate(func, deg, args=()):
1781
"""Interpolate a function at the Chebyshev points of the first kind.
1782
1783
Returns the Chebyshev series that interpolates `func` at the Chebyshev
1784
points of the first kind in the interval [-1, 1]. The interpolating
1785
series tends to a minmax approximation to `func` with increasing `deg`
1786
if the function is continuous in the interval.
1787
1788
.. versionadded:: 1.14.0
1789
1790
Parameters
1791
----------
1792
func : function
1793
The function to be approximated. It must be a function of a single
1794
variable of the form ``f(x, a, b, c...)``, where ``a, b, c...`` are
1795
extra arguments passed in the `args` parameter.
1796
deg : int
1797
Degree of the interpolating polynomial
1798
args : tuple, optional
1799
Extra arguments to be used in the function call. Default is no extra
1800
arguments.
1801
1802
Returns
1803
-------
1804
coef : ndarray, shape (deg + 1,)
1805
Chebyshev coefficients of the interpolating series ordered from low to
1806
high.
1807
1808
Examples
1809
--------
1810
>>> import numpy.polynomial.chebyshev as C
1811
>>> C.chebfromfunction(lambda x: np.tanh(x) + 0.5, 8)
1812
array([ 5.00000000e-01, 8.11675684e-01, -9.86864911e-17,
1813
-5.42457905e-02, -2.71387850e-16, 4.51658839e-03,
1814
2.46716228e-17, -3.79694221e-04, -3.26899002e-16])
1815
1816
Notes
1817
-----
1818
1819
The Chebyshev polynomials used in the interpolation are orthogonal when
1820
sampled at the Chebyshev points of the first kind. If it is desired to
1821
constrain some of the coefficients they can simply be set to the desired
1822
value after the interpolation, no new interpolation or fit is needed. This
1823
is especially useful if it is known apriori that some of coefficients are
1824
zero. For instance, if the function is even then the coefficients of the
1825
terms of odd degree in the result can be set to zero.
1826
1827
"""
1828
deg = np.asarray(deg)
1829
1830
# check arguments.
1831
if deg.ndim > 0 or deg.dtype.kind not in 'iu' or deg.size == 0:
1832
raise TypeError("deg must be an int")
1833
if deg < 0:
1834
raise ValueError("expected deg >= 0")
1835
1836
order = deg + 1
1837
xcheb = chebpts1(order)
1838
yfunc = func(xcheb, *args)
1839
m = chebvander(xcheb, deg)
1840
c = np.dot(m.T, yfunc)
1841
c[0] /= order
1842
c[1:] /= 0.5*order
1843
1844
return c
1845
1846
1847
def chebgauss(deg):
1848
"""
1849
Gauss-Chebyshev quadrature.
1850
1851
Computes the sample points and weights for Gauss-Chebyshev quadrature.
1852
These sample points and weights will correctly integrate polynomials of
1853
degree :math:`2*deg - 1` or less over the interval :math:`[-1, 1]` with
1854
the weight function :math:`f(x) = 1/\\sqrt{1 - x^2}`.
1855
1856
Parameters
1857
----------
1858
deg : int
1859
Number of sample points and weights. It must be >= 1.
1860
1861
Returns
1862
-------
1863
x : ndarray
1864
1-D ndarray containing the sample points.
1865
y : ndarray
1866
1-D ndarray containing the weights.
1867
1868
Notes
1869
-----
1870
1871
.. versionadded:: 1.7.0
1872
1873
The results have only been tested up to degree 100, higher degrees may
1874
be problematic. For Gauss-Chebyshev there are closed form solutions for
1875
the sample points and weights. If n = `deg`, then
1876
1877
.. math:: x_i = \\cos(\\pi (2 i - 1) / (2 n))
1878
1879
.. math:: w_i = \\pi / n
1880
1881
"""
1882
ideg = pu._deprecate_as_int(deg, "deg")
1883
if ideg <= 0:
1884
raise ValueError("deg must be a positive integer")
1885
1886
x = np.cos(np.pi * np.arange(1, 2*ideg, 2) / (2.0*ideg))
1887
w = np.ones(ideg)*(np.pi/ideg)
1888
1889
return x, w
1890
1891
1892
def chebweight(x):
1893
"""
1894
The weight function of the Chebyshev polynomials.
1895
1896
The weight function is :math:`1/\\sqrt{1 - x^2}` and the interval of
1897
integration is :math:`[-1, 1]`. The Chebyshev polynomials are
1898
orthogonal, but not normalized, with respect to this weight function.
1899
1900
Parameters
1901
----------
1902
x : array_like
1903
Values at which the weight function will be computed.
1904
1905
Returns
1906
-------
1907
w : ndarray
1908
The weight function at `x`.
1909
1910
Notes
1911
-----
1912
1913
.. versionadded:: 1.7.0
1914
1915
"""
1916
w = 1./(np.sqrt(1. + x) * np.sqrt(1. - x))
1917
return w
1918
1919
1920
def chebpts1(npts):
1921
"""
1922
Chebyshev points of the first kind.
1923
1924
The Chebyshev points of the first kind are the points ``cos(x)``,
1925
where ``x = [pi*(k + .5)/npts for k in range(npts)]``.
1926
1927
Parameters
1928
----------
1929
npts : int
1930
Number of sample points desired.
1931
1932
Returns
1933
-------
1934
pts : ndarray
1935
The Chebyshev points of the first kind.
1936
1937
See Also
1938
--------
1939
chebpts2
1940
1941
Notes
1942
-----
1943
1944
.. versionadded:: 1.5.0
1945
1946
"""
1947
_npts = int(npts)
1948
if _npts != npts:
1949
raise ValueError("npts must be integer")
1950
if _npts < 1:
1951
raise ValueError("npts must be >= 1")
1952
1953
x = 0.5 * np.pi / _npts * np.arange(-_npts+1, _npts+1, 2)
1954
return np.sin(x)
1955
1956
1957
def chebpts2(npts):
1958
"""
1959
Chebyshev points of the second kind.
1960
1961
The Chebyshev points of the second kind are the points ``cos(x)``,
1962
where ``x = [pi*k/(npts - 1) for k in range(npts)]``.
1963
1964
Parameters
1965
----------
1966
npts : int
1967
Number of sample points desired.
1968
1969
Returns
1970
-------
1971
pts : ndarray
1972
The Chebyshev points of the second kind.
1973
1974
Notes
1975
-----
1976
1977
.. versionadded:: 1.5.0
1978
1979
"""
1980
_npts = int(npts)
1981
if _npts != npts:
1982
raise ValueError("npts must be integer")
1983
if _npts < 2:
1984
raise ValueError("npts must be >= 2")
1985
1986
x = np.linspace(-np.pi, 0, _npts)
1987
return np.cos(x)
1988
1989
1990
#
1991
# Chebyshev series class
1992
#
1993
1994
class Chebyshev(ABCPolyBase):
1995
"""A Chebyshev series class.
1996
1997
The Chebyshev class provides the standard Python numerical methods
1998
'+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the
1999
methods listed below.
2000
2001
Parameters
2002
----------
2003
coef : array_like
2004
Chebyshev coefficients in order of increasing degree, i.e.,
2005
``(1, 2, 3)`` gives ``1*T_0(x) + 2*T_1(x) + 3*T_2(x)``.
2006
domain : (2,) array_like, optional
2007
Domain to use. The interval ``[domain[0], domain[1]]`` is mapped
2008
to the interval ``[window[0], window[1]]`` by shifting and scaling.
2009
The default value is [-1, 1].
2010
window : (2,) array_like, optional
2011
Window, see `domain` for its use. The default value is [-1, 1].
2012
2013
.. versionadded:: 1.6.0
2014
2015
"""
2016
# Virtual Functions
2017
_add = staticmethod(chebadd)
2018
_sub = staticmethod(chebsub)
2019
_mul = staticmethod(chebmul)
2020
_div = staticmethod(chebdiv)
2021
_pow = staticmethod(chebpow)
2022
_val = staticmethod(chebval)
2023
_int = staticmethod(chebint)
2024
_der = staticmethod(chebder)
2025
_fit = staticmethod(chebfit)
2026
_line = staticmethod(chebline)
2027
_roots = staticmethod(chebroots)
2028
_fromroots = staticmethod(chebfromroots)
2029
2030
@classmethod
2031
def interpolate(cls, func, deg, domain=None, args=()):
2032
"""Interpolate a function at the Chebyshev points of the first kind.
2033
2034
Returns the series that interpolates `func` at the Chebyshev points of
2035
the first kind scaled and shifted to the `domain`. The resulting series
2036
tends to a minmax approximation of `func` when the function is
2037
continuous in the domain.
2038
2039
.. versionadded:: 1.14.0
2040
2041
Parameters
2042
----------
2043
func : function
2044
The function to be interpolated. It must be a function of a single
2045
variable of the form ``f(x, a, b, c...)``, where ``a, b, c...`` are
2046
extra arguments passed in the `args` parameter.
2047
deg : int
2048
Degree of the interpolating polynomial.
2049
domain : {None, [beg, end]}, optional
2050
Domain over which `func` is interpolated. The default is None, in
2051
which case the domain is [-1, 1].
2052
args : tuple, optional
2053
Extra arguments to be used in the function call. Default is no
2054
extra arguments.
2055
2056
Returns
2057
-------
2058
polynomial : Chebyshev instance
2059
Interpolating Chebyshev instance.
2060
2061
Notes
2062
-----
2063
See `numpy.polynomial.chebfromfunction` for more details.
2064
2065
"""
2066
if domain is None:
2067
domain = cls.domain
2068
xfunc = lambda x: func(pu.mapdomain(x, cls.window, domain), *args)
2069
coef = chebinterpolate(xfunc, deg)
2070
return cls(coef, domain=domain)
2071
2072
# Virtual properties
2073
domain = np.array(chebdomain)
2074
window = np.array(chebdomain)
2075
basis_name = 'T'
2076
2077