comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/polynomial/chebyshev.py @ 87:2a2c65a20a8b

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