Mercurial > hg > vamp-build-and-test
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) |