Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/numpy/polynomial/chebyshev.py
7763 views
"""1====================================================2Chebyshev Series (:mod:`numpy.polynomial.chebyshev`)3====================================================45This module provides a number of objects (mostly functions) useful for6dealing with Chebyshev series, including a `Chebyshev` class that7encapsulates the usual arithmetic operations. (General information8on how this module represents and works with such polynomials is in the9docstring for its "parent" sub-package, `numpy.polynomial`).1011Classes12-------1314.. autosummary::15:toctree: generated/1617Chebyshev181920Constants21---------2223.. autosummary::24:toctree: generated/2526chebdomain27chebzero28chebone29chebx3031Arithmetic32----------3334.. autosummary::35:toctree: generated/3637chebadd38chebsub39chebmulx40chebmul41chebdiv42chebpow43chebval44chebval2d45chebval3d46chebgrid2d47chebgrid3d4849Calculus50--------5152.. autosummary::53:toctree: generated/5455chebder56chebint5758Misc Functions59--------------6061.. autosummary::62:toctree: generated/6364chebfromroots65chebroots66chebvander67chebvander2d68chebvander3d69chebgauss70chebweight71chebcompanion72chebfit73chebpts174chebpts275chebtrim76chebline77cheb2poly78poly2cheb79chebinterpolate8081See also82--------83`numpy.polynomial`8485Notes86-----87The implementations of multiplication, division, integration, and88differentiation use the algebraic identities [1]_:8990.. math::91T_n(x) = \\frac{z^n + z^{-n}}{2} \\\\92z\\frac{dx}{dz} = \\frac{z - z^{-1}}{2}.9394where9596.. math:: x = \\frac{z + z^{-1}}{2}.9798These identities allow a Chebyshev series to be expressed as a finite,99symmetric Laurent series. In this module, this sort of Laurent series100is referred to as a "z-series."101102References103----------104.. [1] A. T. Benjamin, et al., "Combinatorial Trigonometry with Chebyshev105Polynomials," *Journal of Statistical Planning and Inference 14*, 2008106(https://web.archive.org/web/20080221202153/https://www.math.hmc.edu/~benjamin/papers/CombTrig.pdf, pg. 4)107108"""109import numpy as np110import numpy.linalg as la111from numpy.core.multiarray import normalize_axis_index112113from . import polyutils as pu114from ._polybase import ABCPolyBase115116__all__ = [117'chebzero', 'chebone', 'chebx', 'chebdomain', 'chebline', 'chebadd',118'chebsub', 'chebmulx', 'chebmul', 'chebdiv', 'chebpow', 'chebval',119'chebder', 'chebint', 'cheb2poly', 'poly2cheb', 'chebfromroots',120'chebvander', 'chebfit', 'chebtrim', 'chebroots', 'chebpts1',121'chebpts2', 'Chebyshev', 'chebval2d', 'chebval3d', 'chebgrid2d',122'chebgrid3d', 'chebvander2d', 'chebvander3d', 'chebcompanion',123'chebgauss', 'chebweight', 'chebinterpolate']124125chebtrim = pu.trimcoef126127#128# A collection of functions for manipulating z-series. These are private129# functions and do minimal error checking.130#131132def _cseries_to_zseries(c):133"""Convert Chebyshev series to z-series.134135Convert a Chebyshev series to the equivalent z-series. The result is136never an empty array. The dtype of the return is the same as that of137the input. No checks are run on the arguments as this routine is for138internal use.139140Parameters141----------142c : 1-D ndarray143Chebyshev coefficients, ordered from low to high144145Returns146-------147zs : 1-D ndarray148Odd length symmetric z-series, ordered from low to high.149150"""151n = c.size152zs = np.zeros(2*n-1, dtype=c.dtype)153zs[n-1:] = c/2154return zs + zs[::-1]155156157def _zseries_to_cseries(zs):158"""Convert z-series to a Chebyshev series.159160Convert a z series to the equivalent Chebyshev series. The result is161never an empty array. The dtype of the return is the same as that of162the input. No checks are run on the arguments as this routine is for163internal use.164165Parameters166----------167zs : 1-D ndarray168Odd length symmetric z-series, ordered from low to high.169170Returns171-------172c : 1-D ndarray173Chebyshev coefficients, ordered from low to high.174175"""176n = (zs.size + 1)//2177c = zs[n-1:].copy()178c[1:n] *= 2179return c180181182def _zseries_mul(z1, z2):183"""Multiply two z-series.184185Multiply two z-series to produce a z-series.186187Parameters188----------189z1, z2 : 1-D ndarray190The arrays must be 1-D but this is not checked.191192Returns193-------194product : 1-D ndarray195The product z-series.196197Notes198-----199This is simply convolution. If symmetric/anti-symmetric z-series are200denoted by S/A then the following rules apply:201202S*S, A*A -> S203S*A, A*S -> A204205"""206return np.convolve(z1, z2)207208209def _zseries_div(z1, z2):210"""Divide the first z-series by the second.211212Divide `z1` by `z2` and return the quotient and remainder as z-series.213Warning: this implementation only applies when both z1 and z2 have the214same symmetry, which is sufficient for present purposes.215216Parameters217----------218z1, z2 : 1-D ndarray219The arrays must be 1-D and have the same symmetry, but this is not220checked.221222Returns223-------224225(quotient, remainder) : 1-D ndarrays226Quotient and remainder as z-series.227228Notes229-----230This is not the same as polynomial division on account of the desired form231of the remainder. If symmetric/anti-symmetric z-series are denoted by S/A232then the following rules apply:233234S/S -> S,S235A/A -> S,A236237The restriction to types of the same symmetry could be fixed but seems like238unneeded generality. There is no natural form for the remainder in the case239where there is no symmetry.240241"""242z1 = z1.copy()243z2 = z2.copy()244lc1 = len(z1)245lc2 = len(z2)246if lc2 == 1:247z1 /= z2248return z1, z1[:1]*0249elif lc1 < lc2:250return z1[:1]*0, z1251else:252dlen = lc1 - lc2253scl = z2[0]254z2 /= scl255quo = np.empty(dlen + 1, dtype=z1.dtype)256i = 0257j = dlen258while i < j:259r = z1[i]260quo[i] = z1[i]261quo[dlen - i] = r262tmp = r*z2263z1[i:i+lc2] -= tmp264z1[j:j+lc2] -= tmp265i += 1266j -= 1267r = z1[i]268quo[i] = r269tmp = r*z2270z1[i:i+lc2] -= tmp271quo /= scl272rem = z1[i+1:i-1+lc2].copy()273return quo, rem274275276def _zseries_der(zs):277"""Differentiate a z-series.278279The derivative is with respect to x, not z. This is achieved using the280chain rule and the value of dx/dz given in the module notes.281282Parameters283----------284zs : z-series285The z-series to differentiate.286287Returns288-------289derivative : z-series290The derivative291292Notes293-----294The zseries for x (ns) has been multiplied by two in order to avoid295using floats that are incompatible with Decimal and likely other296specialized scalar types. This scaling has been compensated by297multiplying the value of zs by two also so that the two cancels in the298division.299300"""301n = len(zs)//2302ns = np.array([-1, 0, 1], dtype=zs.dtype)303zs *= np.arange(-n, n+1)*2304d, r = _zseries_div(zs, ns)305return d306307308def _zseries_int(zs):309"""Integrate a z-series.310311The integral is with respect to x, not z. This is achieved by a change312of variable using dx/dz given in the module notes.313314Parameters315----------316zs : z-series317The z-series to integrate318319Returns320-------321integral : z-series322The indefinite integral323324Notes325-----326The zseries for x (ns) has been multiplied by two in order to avoid327using floats that are incompatible with Decimal and likely other328specialized scalar types. This scaling has been compensated by329dividing the resulting zs by two.330331"""332n = 1 + len(zs)//2333ns = np.array([-1, 0, 1], dtype=zs.dtype)334zs = _zseries_mul(zs, ns)335div = np.arange(-n, n+1)*2336zs[:n] /= div[:n]337zs[n+1:] /= div[n+1:]338zs[n] = 0339return zs340341#342# Chebyshev series functions343#344345346def poly2cheb(pol):347"""348Convert a polynomial to a Chebyshev series.349350Convert an array representing the coefficients of a polynomial (relative351to the "standard" basis) ordered from lowest degree to highest, to an352array of the coefficients of the equivalent Chebyshev series, ordered353from lowest to highest degree.354355Parameters356----------357pol : array_like3581-D array containing the polynomial coefficients359360Returns361-------362c : ndarray3631-D array containing the coefficients of the equivalent Chebyshev364series.365366See Also367--------368cheb2poly369370Notes371-----372The easy way to do conversions between polynomial basis sets373is to use the convert method of a class instance.374375Examples376--------377>>> from numpy import polynomial as P378>>> p = P.Polynomial(range(4))379>>> p380Polynomial([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])381>>> c = p.convert(kind=P.Chebyshev)382>>> c383Chebyshev([1. , 3.25, 1. , 0.75], domain=[-1., 1.], window=[-1., 1.])384>>> P.chebyshev.poly2cheb(range(4))385array([1. , 3.25, 1. , 0.75])386387"""388[pol] = pu.as_series([pol])389deg = len(pol) - 1390res = 0391for i in range(deg, -1, -1):392res = chebadd(chebmulx(res), pol[i])393return res394395396def cheb2poly(c):397"""398Convert a Chebyshev series to a polynomial.399400Convert an array representing the coefficients of a Chebyshev series,401ordered from lowest degree to highest, to an array of the coefficients402of the equivalent polynomial (relative to the "standard" basis) ordered403from lowest to highest degree.404405Parameters406----------407c : array_like4081-D array containing the Chebyshev series coefficients, ordered409from lowest order term to highest.410411Returns412-------413pol : ndarray4141-D array containing the coefficients of the equivalent polynomial415(relative to the "standard" basis) ordered from lowest order term416to highest.417418See Also419--------420poly2cheb421422Notes423-----424The easy way to do conversions between polynomial basis sets425is to use the convert method of a class instance.426427Examples428--------429>>> from numpy import polynomial as P430>>> c = P.Chebyshev(range(4))431>>> c432Chebyshev([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])433>>> p = c.convert(kind=P.Polynomial)434>>> p435Polynomial([-2., -8., 4., 12.], domain=[-1., 1.], window=[-1., 1.])436>>> P.chebyshev.cheb2poly(range(4))437array([-2., -8., 4., 12.])438439"""440from .polynomial import polyadd, polysub, polymulx441442[c] = pu.as_series([c])443n = len(c)444if n < 3:445return c446else:447c0 = c[-2]448c1 = c[-1]449# i is the current degree of c1450for i in range(n - 1, 1, -1):451tmp = c0452c0 = polysub(c[i - 2], c1)453c1 = polyadd(tmp, polymulx(c1)*2)454return polyadd(c0, polymulx(c1))455456457#458# These are constant arrays are of integer type so as to be compatible459# with the widest range of other types, such as Decimal.460#461462# Chebyshev default domain.463chebdomain = np.array([-1, 1])464465# Chebyshev coefficients representing zero.466chebzero = np.array([0])467468# Chebyshev coefficients representing one.469chebone = np.array([1])470471# Chebyshev coefficients representing the identity x.472chebx = np.array([0, 1])473474475def chebline(off, scl):476"""477Chebyshev series whose graph is a straight line.478479Parameters480----------481off, scl : scalars482The specified line is given by ``off + scl*x``.483484Returns485-------486y : ndarray487This module's representation of the Chebyshev series for488``off + scl*x``.489490See Also491--------492numpy.polynomial.polynomial.polyline493numpy.polynomial.legendre.legline494numpy.polynomial.laguerre.lagline495numpy.polynomial.hermite.hermline496numpy.polynomial.hermite_e.hermeline497498Examples499--------500>>> import numpy.polynomial.chebyshev as C501>>> C.chebline(3,2)502array([3, 2])503>>> C.chebval(-3, C.chebline(3,2)) # should be -3504-3.0505506"""507if scl != 0:508return np.array([off, scl])509else:510return np.array([off])511512513def chebfromroots(roots):514"""515Generate a Chebyshev series with given roots.516517The function returns the coefficients of the polynomial518519.. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n),520521in Chebyshev form, where the `r_n` are the roots specified in `roots`.522If a zero has multiplicity n, then it must appear in `roots` n times.523For instance, if 2 is a root of multiplicity three and 3 is a root of524multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The525roots can appear in any order.526527If the returned coefficients are `c`, then528529.. math:: p(x) = c_0 + c_1 * T_1(x) + ... + c_n * T_n(x)530531The coefficient of the last term is not generally 1 for monic532polynomials in Chebyshev form.533534Parameters535----------536roots : array_like537Sequence containing the roots.538539Returns540-------541out : ndarray5421-D array of coefficients. If all roots are real then `out` is a543real array, if some of the roots are complex, then `out` is complex544even if all the coefficients in the result are real (see Examples545below).546547See Also548--------549numpy.polynomial.polynomial.polyfromroots550numpy.polynomial.legendre.legfromroots551numpy.polynomial.laguerre.lagfromroots552numpy.polynomial.hermite.hermfromroots553numpy.polynomial.hermite_e.hermefromroots554555Examples556--------557>>> import numpy.polynomial.chebyshev as C558>>> C.chebfromroots((-1,0,1)) # x^3 - x relative to the standard basis559array([ 0. , -0.25, 0. , 0.25])560>>> j = complex(0,1)561>>> C.chebfromroots((-j,j)) # x^2 + 1 relative to the standard basis562array([1.5+0.j, 0. +0.j, 0.5+0.j])563564"""565return pu._fromroots(chebline, chebmul, roots)566567568def chebadd(c1, c2):569"""570Add one Chebyshev series to another.571572Returns the sum of two Chebyshev series `c1` + `c2`. The arguments573are sequences of coefficients ordered from lowest order term to574highest, i.e., [1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``.575576Parameters577----------578c1, c2 : array_like5791-D arrays of Chebyshev series coefficients ordered from low to580high.581582Returns583-------584out : ndarray585Array representing the Chebyshev series of their sum.586587See Also588--------589chebsub, chebmulx, chebmul, chebdiv, chebpow590591Notes592-----593Unlike multiplication, division, etc., the sum of two Chebyshev series594is a Chebyshev series (without having to "reproject" the result onto595the basis set) so addition, just like that of "standard" polynomials,596is simply "component-wise."597598Examples599--------600>>> from numpy.polynomial import chebyshev as C601>>> c1 = (1,2,3)602>>> c2 = (3,2,1)603>>> C.chebadd(c1,c2)604array([4., 4., 4.])605606"""607return pu._add(c1, c2)608609610def chebsub(c1, c2):611"""612Subtract one Chebyshev series from another.613614Returns the difference of two Chebyshev series `c1` - `c2`. The615sequences of coefficients are from lowest order term to highest, i.e.,616[1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``.617618Parameters619----------620c1, c2 : array_like6211-D arrays of Chebyshev series coefficients ordered from low to622high.623624Returns625-------626out : ndarray627Of Chebyshev series coefficients representing their difference.628629See Also630--------631chebadd, chebmulx, chebmul, chebdiv, chebpow632633Notes634-----635Unlike multiplication, division, etc., the difference of two Chebyshev636series is a Chebyshev series (without having to "reproject" the result637onto the basis set) so subtraction, just like that of "standard"638polynomials, is simply "component-wise."639640Examples641--------642>>> from numpy.polynomial import chebyshev as C643>>> c1 = (1,2,3)644>>> c2 = (3,2,1)645>>> C.chebsub(c1,c2)646array([-2., 0., 2.])647>>> C.chebsub(c2,c1) # -C.chebsub(c1,c2)648array([ 2., 0., -2.])649650"""651return pu._sub(c1, c2)652653654def chebmulx(c):655"""Multiply a Chebyshev series by x.656657Multiply the polynomial `c` by x, where x is the independent658variable.659660661Parameters662----------663c : array_like6641-D array of Chebyshev series coefficients ordered from low to665high.666667Returns668-------669out : ndarray670Array representing the result of the multiplication.671672Notes673-----674675.. versionadded:: 1.5.0676677Examples678--------679>>> from numpy.polynomial import chebyshev as C680>>> C.chebmulx([1,2,3])681array([1. , 2.5, 1. , 1.5])682683"""684# c is a trimmed copy685[c] = pu.as_series([c])686# The zero series needs special treatment687if len(c) == 1 and c[0] == 0:688return c689690prd = np.empty(len(c) + 1, dtype=c.dtype)691prd[0] = c[0]*0692prd[1] = c[0]693if len(c) > 1:694tmp = c[1:]/2695prd[2:] = tmp696prd[0:-2] += tmp697return prd698699700def chebmul(c1, c2):701"""702Multiply one Chebyshev series by another.703704Returns the product of two Chebyshev series `c1` * `c2`. The arguments705are sequences of coefficients, from lowest order "term" to highest,706e.g., [1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``.707708Parameters709----------710c1, c2 : array_like7111-D arrays of Chebyshev series coefficients ordered from low to712high.713714Returns715-------716out : ndarray717Of Chebyshev series coefficients representing their product.718719See Also720--------721chebadd, chebsub, chebmulx, chebdiv, chebpow722723Notes724-----725In general, the (polynomial) product of two C-series results in terms726that are not in the Chebyshev polynomial basis set. Thus, to express727the product as a C-series, it is typically necessary to "reproject"728the product onto said basis set, which typically produces729"unintuitive live" (but correct) results; see Examples section below.730731Examples732--------733>>> from numpy.polynomial import chebyshev as C734>>> c1 = (1,2,3)735>>> c2 = (3,2,1)736>>> C.chebmul(c1,c2) # multiplication requires "reprojection"737array([ 6.5, 12. , 12. , 4. , 1.5])738739"""740# c1, c2 are trimmed copies741[c1, c2] = pu.as_series([c1, c2])742z1 = _cseries_to_zseries(c1)743z2 = _cseries_to_zseries(c2)744prd = _zseries_mul(z1, z2)745ret = _zseries_to_cseries(prd)746return pu.trimseq(ret)747748749def chebdiv(c1, c2):750"""751Divide one Chebyshev series by another.752753Returns the quotient-with-remainder of two Chebyshev series754`c1` / `c2`. The arguments are sequences of coefficients from lowest755order "term" to highest, e.g., [1,2,3] represents the series756``T_0 + 2*T_1 + 3*T_2``.757758Parameters759----------760c1, c2 : array_like7611-D arrays of Chebyshev series coefficients ordered from low to762high.763764Returns765-------766[quo, rem] : ndarrays767Of Chebyshev series coefficients representing the quotient and768remainder.769770See Also771--------772chebadd, chebsub, chebmulx, chebmul, chebpow773774Notes775-----776In general, the (polynomial) division of one C-series by another777results in quotient and remainder terms that are not in the Chebyshev778polynomial basis set. Thus, to express these results as C-series, it779is typically necessary to "reproject" the results onto said basis780set, which typically produces "unintuitive" (but correct) results;781see Examples section below.782783Examples784--------785>>> from numpy.polynomial import chebyshev as C786>>> c1 = (1,2,3)787>>> c2 = (3,2,1)788>>> C.chebdiv(c1,c2) # quotient "intuitive," remainder not789(array([3.]), array([-8., -4.]))790>>> c2 = (0,1,2,3)791>>> C.chebdiv(c2,c1) # neither "intuitive"792(array([0., 2.]), array([-2., -4.]))793794"""795# c1, c2 are trimmed copies796[c1, c2] = pu.as_series([c1, c2])797if c2[-1] == 0:798raise ZeroDivisionError()799800# note: this is more efficient than `pu._div(chebmul, c1, c2)`801lc1 = len(c1)802lc2 = len(c2)803if lc1 < lc2:804return c1[:1]*0, c1805elif lc2 == 1:806return c1/c2[-1], c1[:1]*0807else:808z1 = _cseries_to_zseries(c1)809z2 = _cseries_to_zseries(c2)810quo, rem = _zseries_div(z1, z2)811quo = pu.trimseq(_zseries_to_cseries(quo))812rem = pu.trimseq(_zseries_to_cseries(rem))813return quo, rem814815816def chebpow(c, pow, maxpower=16):817"""Raise a Chebyshev series to a power.818819Returns the Chebyshev series `c` raised to the power `pow`. The820argument `c` is a sequence of coefficients ordered from low to high.821i.e., [1,2,3] is the series ``T_0 + 2*T_1 + 3*T_2.``822823Parameters824----------825c : array_like8261-D array of Chebyshev series coefficients ordered from low to827high.828pow : integer829Power to which the series will be raised830maxpower : integer, optional831Maximum power allowed. This is mainly to limit growth of the series832to unmanageable size. Default is 16833834Returns835-------836coef : ndarray837Chebyshev series of power.838839See Also840--------841chebadd, chebsub, chebmulx, chebmul, chebdiv842843Examples844--------845>>> from numpy.polynomial import chebyshev as C846>>> C.chebpow([1, 2, 3, 4], 2)847array([15.5, 22. , 16. , ..., 12.5, 12. , 8. ])848849"""850# note: this is more efficient than `pu._pow(chebmul, c1, c2)`, as it851# avoids converting between z and c series repeatedly852853# c is a trimmed copy854[c] = pu.as_series([c])855power = int(pow)856if power != pow or power < 0:857raise ValueError("Power must be a non-negative integer.")858elif maxpower is not None and power > maxpower:859raise ValueError("Power is too large")860elif power == 0:861return np.array([1], dtype=c.dtype)862elif power == 1:863return c864else:865# This can be made more efficient by using powers of two866# in the usual way.867zs = _cseries_to_zseries(c)868prd = zs869for i in range(2, power + 1):870prd = np.convolve(prd, zs)871return _zseries_to_cseries(prd)872873874def chebder(c, m=1, scl=1, axis=0):875"""876Differentiate a Chebyshev series.877878Returns the Chebyshev series coefficients `c` differentiated `m` times879along `axis`. At each iteration the result is multiplied by `scl` (the880scaling factor is for use in a linear change of variable). The argument881`c` is an array of coefficients from low to high degree along each882axis, e.g., [1,2,3] represents the series ``1*T_0 + 2*T_1 + 3*T_2``883while [[1,2],[1,2]] represents ``1*T_0(x)*T_0(y) + 1*T_1(x)*T_0(y) +8842*T_0(x)*T_1(y) + 2*T_1(x)*T_1(y)`` if axis=0 is ``x`` and axis=1 is885``y``.886887Parameters888----------889c : array_like890Array of Chebyshev series coefficients. If c is multidimensional891the different axis correspond to different variables with the892degree in each axis given by the corresponding index.893m : int, optional894Number of derivatives taken, must be non-negative. (Default: 1)895scl : scalar, optional896Each differentiation is multiplied by `scl`. The end result is897multiplication by ``scl**m``. This is for use in a linear change of898variable. (Default: 1)899axis : int, optional900Axis over which the derivative is taken. (Default: 0).901902.. versionadded:: 1.7.0903904Returns905-------906der : ndarray907Chebyshev series of the derivative.908909See Also910--------911chebint912913Notes914-----915In general, the result of differentiating a C-series needs to be916"reprojected" onto the C-series basis set. Thus, typically, the917result of this function is "unintuitive," albeit correct; see Examples918section below.919920Examples921--------922>>> from numpy.polynomial import chebyshev as C923>>> c = (1,2,3,4)924>>> C.chebder(c)925array([14., 12., 24.])926>>> C.chebder(c,3)927array([96.])928>>> C.chebder(c,scl=-1)929array([-14., -12., -24.])930>>> C.chebder(c,2,-1)931array([12., 96.])932933"""934c = np.array(c, ndmin=1, copy=True)935if c.dtype.char in '?bBhHiIlLqQpP':936c = c.astype(np.double)937cnt = pu._deprecate_as_int(m, "the order of derivation")938iaxis = pu._deprecate_as_int(axis, "the axis")939if cnt < 0:940raise ValueError("The order of derivation must be non-negative")941iaxis = normalize_axis_index(iaxis, c.ndim)942943if cnt == 0:944return c945946c = np.moveaxis(c, iaxis, 0)947n = len(c)948if cnt >= n:949c = c[:1]*0950else:951for i in range(cnt):952n = n - 1953c *= scl954der = np.empty((n,) + c.shape[1:], dtype=c.dtype)955for j in range(n, 2, -1):956der[j - 1] = (2*j)*c[j]957c[j - 2] += (j*c[j])/(j - 2)958if n > 1:959der[1] = 4*c[2]960der[0] = c[1]961c = der962c = np.moveaxis(c, 0, iaxis)963return c964965966def chebint(c, m=1, k=[], lbnd=0, scl=1, axis=0):967"""968Integrate a Chebyshev series.969970Returns the Chebyshev series coefficients `c` integrated `m` times from971`lbnd` along `axis`. At each iteration the resulting series is972**multiplied** by `scl` and an integration constant, `k`, is added.973The scaling factor is for use in a linear change of variable. ("Buyer974beware": note that, depending on what one is doing, one may want `scl`975to be the reciprocal of what one might expect; for more information,976see the Notes section below.) The argument `c` is an array of977coefficients from low to high degree along each axis, e.g., [1,2,3]978represents the series ``T_0 + 2*T_1 + 3*T_2`` while [[1,2],[1,2]]979represents ``1*T_0(x)*T_0(y) + 1*T_1(x)*T_0(y) + 2*T_0(x)*T_1(y) +9802*T_1(x)*T_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.981982Parameters983----------984c : array_like985Array of Chebyshev series coefficients. If c is multidimensional986the different axis correspond to different variables with the987degree in each axis given by the corresponding index.988m : int, optional989Order of integration, must be positive. (Default: 1)990k : {[], list, scalar}, optional991Integration constant(s). The value of the first integral at zero992is the first value in the list, the value of the second integral993at zero is the second value, etc. If ``k == []`` (the default),994all constants are set to zero. If ``m == 1``, a single scalar can995be given instead of a list.996lbnd : scalar, optional997The lower bound of the integral. (Default: 0)998scl : scalar, optional999Following each integration the result is *multiplied* by `scl`1000before the integration constant is added. (Default: 1)1001axis : int, optional1002Axis over which the integral is taken. (Default: 0).10031004.. versionadded:: 1.7.010051006Returns1007-------1008S : ndarray1009C-series coefficients of the integral.10101011Raises1012------1013ValueError1014If ``m < 1``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or1015``np.ndim(scl) != 0``.10161017See Also1018--------1019chebder10201021Notes1022-----1023Note that the result of each integration is *multiplied* by `scl`.1024Why is this important to note? Say one is making a linear change of1025variable :math:`u = ax + b` in an integral relative to `x`. Then1026:math:`dx = du/a`, so one will need to set `scl` equal to1027:math:`1/a`- perhaps not what one would have first thought.10281029Also note that, in general, the result of integrating a C-series needs1030to be "reprojected" onto the C-series basis set. Thus, typically,1031the result of this function is "unintuitive," albeit correct; see1032Examples section below.10331034Examples1035--------1036>>> from numpy.polynomial import chebyshev as C1037>>> c = (1,2,3)1038>>> C.chebint(c)1039array([ 0.5, -0.5, 0.5, 0.5])1040>>> C.chebint(c,3)1041array([ 0.03125 , -0.1875 , 0.04166667, -0.05208333, 0.01041667, # may vary10420.00625 ])1043>>> C.chebint(c, k=3)1044array([ 3.5, -0.5, 0.5, 0.5])1045>>> C.chebint(c,lbnd=-2)1046array([ 8.5, -0.5, 0.5, 0.5])1047>>> C.chebint(c,scl=-2)1048array([-1., 1., -1., -1.])10491050"""1051c = np.array(c, ndmin=1, copy=True)1052if c.dtype.char in '?bBhHiIlLqQpP':1053c = c.astype(np.double)1054if not np.iterable(k):1055k = [k]1056cnt = pu._deprecate_as_int(m, "the order of integration")1057iaxis = pu._deprecate_as_int(axis, "the axis")1058if cnt < 0:1059raise ValueError("The order of integration must be non-negative")1060if len(k) > cnt:1061raise ValueError("Too many integration constants")1062if np.ndim(lbnd) != 0:1063raise ValueError("lbnd must be a scalar.")1064if np.ndim(scl) != 0:1065raise ValueError("scl must be a scalar.")1066iaxis = normalize_axis_index(iaxis, c.ndim)10671068if cnt == 0:1069return c10701071c = np.moveaxis(c, iaxis, 0)1072k = list(k) + [0]*(cnt - len(k))1073for i in range(cnt):1074n = len(c)1075c *= scl1076if n == 1 and np.all(c[0] == 0):1077c[0] += k[i]1078else:1079tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)1080tmp[0] = c[0]*01081tmp[1] = c[0]1082if n > 1:1083tmp[2] = c[1]/41084for j in range(2, n):1085tmp[j + 1] = c[j]/(2*(j + 1))1086tmp[j - 1] -= c[j]/(2*(j - 1))1087tmp[0] += k[i] - chebval(lbnd, tmp)1088c = tmp1089c = np.moveaxis(c, 0, iaxis)1090return c109110921093def chebval(x, c, tensor=True):1094"""1095Evaluate a Chebyshev series at points x.10961097If `c` is of length `n + 1`, this function returns the value:10981099.. math:: p(x) = c_0 * T_0(x) + c_1 * T_1(x) + ... + c_n * T_n(x)11001101The parameter `x` is converted to an array only if it is a tuple or a1102list, otherwise it is treated as a scalar. In either case, either `x`1103or its elements must support multiplication and addition both with1104themselves and with the elements of `c`.11051106If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If1107`c` is multidimensional, then the shape of the result depends on the1108value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +1109x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that1110scalars have shape (,).11111112Trailing zeros in the coefficients will be used in the evaluation, so1113they should be avoided if efficiency is a concern.11141115Parameters1116----------1117x : array_like, compatible object1118If `x` is a list or tuple, it is converted to an ndarray, otherwise1119it is left unchanged and treated as a scalar. In either case, `x`1120or its elements must support addition and multiplication with1121with themselves and with the elements of `c`.1122c : array_like1123Array of coefficients ordered so that the coefficients for terms of1124degree n are contained in c[n]. If `c` is multidimensional the1125remaining indices enumerate multiple polynomials. In the two1126dimensional case the coefficients may be thought of as stored in1127the columns of `c`.1128tensor : boolean, optional1129If True, the shape of the coefficient array is extended with ones1130on the right, one for each dimension of `x`. Scalars have dimension 01131for this action. The result is that every column of coefficients in1132`c` is evaluated for every element of `x`. If False, `x` is broadcast1133over the columns of `c` for the evaluation. This keyword is useful1134when `c` is multidimensional. The default value is True.11351136.. versionadded:: 1.7.011371138Returns1139-------1140values : ndarray, algebra_like1141The shape of the return value is described above.11421143See Also1144--------1145chebval2d, chebgrid2d, chebval3d, chebgrid3d11461147Notes1148-----1149The evaluation uses Clenshaw recursion, aka synthetic division.11501151"""1152c = np.array(c, ndmin=1, copy=True)1153if c.dtype.char in '?bBhHiIlLqQpP':1154c = c.astype(np.double)1155if isinstance(x, (tuple, list)):1156x = np.asarray(x)1157if isinstance(x, np.ndarray) and tensor:1158c = c.reshape(c.shape + (1,)*x.ndim)11591160if len(c) == 1:1161c0 = c[0]1162c1 = 01163elif len(c) == 2:1164c0 = c[0]1165c1 = c[1]1166else:1167x2 = 2*x1168c0 = c[-2]1169c1 = c[-1]1170for i in range(3, len(c) + 1):1171tmp = c01172c0 = c[-i] - c11173c1 = tmp + c1*x21174return c0 + c1*x117511761177def chebval2d(x, y, c):1178"""1179Evaluate a 2-D Chebyshev series at points (x, y).11801181This function returns the values:11821183.. math:: p(x,y) = \\sum_{i,j} c_{i,j} * T_i(x) * T_j(y)11841185The parameters `x` and `y` are converted to arrays only if they are1186tuples or a lists, otherwise they are treated as a scalars and they1187must have the same shape after conversion. In either case, either `x`1188and `y` or their elements must support multiplication and addition both1189with themselves and with the elements of `c`.11901191If `c` is a 1-D array a one is implicitly appended to its shape to make1192it 2-D. The shape of the result will be c.shape[2:] + x.shape.11931194Parameters1195----------1196x, y : array_like, compatible objects1197The two dimensional series is evaluated at the points `(x, y)`,1198where `x` and `y` must have the same shape. If `x` or `y` is a list1199or tuple, it is first converted to an ndarray, otherwise it is left1200unchanged and if it isn't an ndarray it is treated as a scalar.1201c : array_like1202Array of coefficients ordered so that the coefficient of the term1203of multi-degree i,j is contained in ``c[i,j]``. If `c` has1204dimension greater than 2 the remaining indices enumerate multiple1205sets of coefficients.12061207Returns1208-------1209values : ndarray, compatible object1210The values of the two dimensional Chebyshev series at points formed1211from pairs of corresponding values from `x` and `y`.12121213See Also1214--------1215chebval, chebgrid2d, chebval3d, chebgrid3d12161217Notes1218-----12191220.. versionadded:: 1.7.012211222"""1223return pu._valnd(chebval, c, x, y)122412251226def chebgrid2d(x, y, c):1227"""1228Evaluate a 2-D Chebyshev series on the Cartesian product of x and y.12291230This function returns the values:12311232.. math:: p(a,b) = \\sum_{i,j} c_{i,j} * T_i(a) * T_j(b),12331234where the points `(a, b)` consist of all pairs formed by taking1235`a` from `x` and `b` from `y`. The resulting points form a grid with1236`x` in the first dimension and `y` in the second.12371238The parameters `x` and `y` are converted to arrays only if they are1239tuples or a lists, otherwise they are treated as a scalars. In either1240case, either `x` and `y` or their elements must support multiplication1241and addition both with themselves and with the elements of `c`.12421243If `c` has fewer than two dimensions, ones are implicitly appended to1244its shape to make it 2-D. The shape of the result will be c.shape[2:] +1245x.shape + y.shape.12461247Parameters1248----------1249x, y : array_like, compatible objects1250The two dimensional series is evaluated at the points in the1251Cartesian product of `x` and `y`. If `x` or `y` is a list or1252tuple, it is first converted to an ndarray, otherwise it is left1253unchanged and, if it isn't an ndarray, it is treated as a scalar.1254c : array_like1255Array of coefficients ordered so that the coefficient of the term of1256multi-degree i,j is contained in `c[i,j]`. If `c` has dimension1257greater than two the remaining indices enumerate multiple sets of1258coefficients.12591260Returns1261-------1262values : ndarray, compatible object1263The values of the two dimensional Chebyshev series at points in the1264Cartesian product of `x` and `y`.12651266See Also1267--------1268chebval, chebval2d, chebval3d, chebgrid3d12691270Notes1271-----12721273.. versionadded:: 1.7.012741275"""1276return pu._gridnd(chebval, c, x, y)127712781279def chebval3d(x, y, z, c):1280"""1281Evaluate a 3-D Chebyshev series at points (x, y, z).12821283This function returns the values:12841285.. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * T_i(x) * T_j(y) * T_k(z)12861287The parameters `x`, `y`, and `z` are converted to arrays only if1288they are tuples or a lists, otherwise they are treated as a scalars and1289they must have the same shape after conversion. In either case, either1290`x`, `y`, and `z` or their elements must support multiplication and1291addition both with themselves and with the elements of `c`.12921293If `c` has fewer than 3 dimensions, ones are implicitly appended to its1294shape to make it 3-D. The shape of the result will be c.shape[3:] +1295x.shape.12961297Parameters1298----------1299x, y, z : array_like, compatible object1300The three dimensional series is evaluated at the points1301`(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If1302any of `x`, `y`, or `z` is a list or tuple, it is first converted1303to an ndarray, otherwise it is left unchanged and if it isn't an1304ndarray it is treated as a scalar.1305c : array_like1306Array of coefficients ordered so that the coefficient of the term of1307multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension1308greater than 3 the remaining indices enumerate multiple sets of1309coefficients.13101311Returns1312-------1313values : ndarray, compatible object1314The values of the multidimensional polynomial on points formed with1315triples of corresponding values from `x`, `y`, and `z`.13161317See Also1318--------1319chebval, chebval2d, chebgrid2d, chebgrid3d13201321Notes1322-----13231324.. versionadded:: 1.7.013251326"""1327return pu._valnd(chebval, c, x, y, z)132813291330def chebgrid3d(x, y, z, c):1331"""1332Evaluate a 3-D Chebyshev series on the Cartesian product of x, y, and z.13331334This function returns the values:13351336.. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * T_i(a) * T_j(b) * T_k(c)13371338where the points `(a, b, c)` consist of all triples formed by taking1339`a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form1340a grid with `x` in the first dimension, `y` in the second, and `z` in1341the third.13421343The parameters `x`, `y`, and `z` are converted to arrays only if they1344are tuples or a lists, otherwise they are treated as a scalars. In1345either case, either `x`, `y`, and `z` or their elements must support1346multiplication and addition both with themselves and with the elements1347of `c`.13481349If `c` has fewer than three dimensions, ones are implicitly appended to1350its shape to make it 3-D. The shape of the result will be c.shape[3:] +1351x.shape + y.shape + z.shape.13521353Parameters1354----------1355x, y, z : array_like, compatible objects1356The three dimensional series is evaluated at the points in the1357Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a1358list or tuple, it is first converted to an ndarray, otherwise it is1359left unchanged and, if it isn't an ndarray, it is treated as a1360scalar.1361c : array_like1362Array of coefficients ordered so that the coefficients for terms of1363degree i,j are contained in ``c[i,j]``. If `c` has dimension1364greater than two the remaining indices enumerate multiple sets of1365coefficients.13661367Returns1368-------1369values : ndarray, compatible object1370The values of the two dimensional polynomial at points in the Cartesian1371product of `x` and `y`.13721373See Also1374--------1375chebval, chebval2d, chebgrid2d, chebval3d13761377Notes1378-----13791380.. versionadded:: 1.7.013811382"""1383return pu._gridnd(chebval, c, x, y, z)138413851386def chebvander(x, deg):1387"""Pseudo-Vandermonde matrix of given degree.13881389Returns the pseudo-Vandermonde matrix of degree `deg` and sample points1390`x`. The pseudo-Vandermonde matrix is defined by13911392.. math:: V[..., i] = T_i(x),13931394where `0 <= i <= deg`. The leading indices of `V` index the elements of1395`x` and the last index is the degree of the Chebyshev polynomial.13961397If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the1398matrix ``V = chebvander(x, n)``, then ``np.dot(V, c)`` and1399``chebval(x, c)`` are the same up to roundoff. This equivalence is1400useful both for least squares fitting and for the evaluation of a large1401number of Chebyshev series of the same degree and sample points.14021403Parameters1404----------1405x : array_like1406Array of points. The dtype is converted to float64 or complex1281407depending on whether any of the elements are complex. If `x` is1408scalar it is converted to a 1-D array.1409deg : int1410Degree of the resulting matrix.14111412Returns1413-------1414vander : ndarray1415The pseudo Vandermonde matrix. The shape of the returned matrix is1416``x.shape + (deg + 1,)``, where The last index is the degree of the1417corresponding Chebyshev polynomial. The dtype will be the same as1418the converted `x`.14191420"""1421ideg = pu._deprecate_as_int(deg, "deg")1422if ideg < 0:1423raise ValueError("deg must be non-negative")14241425x = np.array(x, copy=False, ndmin=1) + 0.01426dims = (ideg + 1,) + x.shape1427dtyp = x.dtype1428v = np.empty(dims, dtype=dtyp)1429# Use forward recursion to generate the entries.1430v[0] = x*0 + 11431if ideg > 0:1432x2 = 2*x1433v[1] = x1434for i in range(2, ideg + 1):1435v[i] = v[i-1]*x2 - v[i-2]1436return np.moveaxis(v, 0, -1)143714381439def chebvander2d(x, y, deg):1440"""Pseudo-Vandermonde matrix of given degrees.14411442Returns the pseudo-Vandermonde matrix of degrees `deg` and sample1443points `(x, y)`. The pseudo-Vandermonde matrix is defined by14441445.. math:: V[..., (deg[1] + 1)*i + j] = T_i(x) * T_j(y),14461447where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of1448`V` index the points `(x, y)` and the last index encodes the degrees of1449the Chebyshev polynomials.14501451If ``V = chebvander2d(x, y, [xdeg, ydeg])``, then the columns of `V`1452correspond to the elements of a 2-D coefficient array `c` of shape1453(xdeg + 1, ydeg + 1) in the order14541455.. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ...14561457and ``np.dot(V, c.flat)`` and ``chebval2d(x, y, c)`` will be the same1458up to roundoff. This equivalence is useful both for least squares1459fitting and for the evaluation of a large number of 2-D Chebyshev1460series of the same degrees and sample points.14611462Parameters1463----------1464x, y : array_like1465Arrays of point coordinates, all of the same shape. The dtypes1466will be converted to either float64 or complex128 depending on1467whether any of the elements are complex. Scalars are converted to14681-D arrays.1469deg : list of ints1470List of maximum degrees of the form [x_deg, y_deg].14711472Returns1473-------1474vander2d : ndarray1475The shape of the returned matrix is ``x.shape + (order,)``, where1476:math:`order = (deg[0]+1)*(deg[1]+1)`. The dtype will be the same1477as the converted `x` and `y`.14781479See Also1480--------1481chebvander, chebvander3d, chebval2d, chebval3d14821483Notes1484-----14851486.. versionadded:: 1.7.014871488"""1489return pu._vander_nd_flat((chebvander, chebvander), (x, y), deg)149014911492def chebvander3d(x, y, z, deg):1493"""Pseudo-Vandermonde matrix of given degrees.14941495Returns the pseudo-Vandermonde matrix of degrees `deg` and sample1496points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`,1497then The pseudo-Vandermonde matrix is defined by14981499.. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = T_i(x)*T_j(y)*T_k(z),15001501where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading1502indices of `V` index the points `(x, y, z)` and the last index encodes1503the degrees of the Chebyshev polynomials.15041505If ``V = chebvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns1506of `V` correspond to the elements of a 3-D coefficient array `c` of1507shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order15081509.. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...15101511and ``np.dot(V, c.flat)`` and ``chebval3d(x, y, z, c)`` will be the1512same up to roundoff. This equivalence is useful both for least squares1513fitting and for the evaluation of a large number of 3-D Chebyshev1514series of the same degrees and sample points.15151516Parameters1517----------1518x, y, z : array_like1519Arrays of point coordinates, all of the same shape. The dtypes will1520be converted to either float64 or complex128 depending on whether1521any of the elements are complex. Scalars are converted to 1-D1522arrays.1523deg : list of ints1524List of maximum degrees of the form [x_deg, y_deg, z_deg].15251526Returns1527-------1528vander3d : ndarray1529The shape of the returned matrix is ``x.shape + (order,)``, where1530:math:`order = (deg[0]+1)*(deg[1]+1)*(deg[2]+1)`. The dtype will1531be the same as the converted `x`, `y`, and `z`.15321533See Also1534--------1535chebvander, chebvander3d, chebval2d, chebval3d15361537Notes1538-----15391540.. versionadded:: 1.7.015411542"""1543return pu._vander_nd_flat((chebvander, chebvander, chebvander), (x, y, z), deg)154415451546def chebfit(x, y, deg, rcond=None, full=False, w=None):1547"""1548Least squares fit of Chebyshev series to data.15491550Return the coefficients of a Chebyshev series of degree `deg` that is the1551least squares fit to the data values `y` given at points `x`. If `y` is15521-D the returned coefficients will also be 1-D. If `y` is 2-D multiple1553fits are done, one for each column of `y`, and the resulting1554coefficients are stored in the corresponding columns of a 2-D return.1555The fitted polynomial(s) are in the form15561557.. math:: p(x) = c_0 + c_1 * T_1(x) + ... + c_n * T_n(x),15581559where `n` is `deg`.15601561Parameters1562----------1563x : array_like, shape (M,)1564x-coordinates of the M sample points ``(x[i], y[i])``.1565y : array_like, shape (M,) or (M, K)1566y-coordinates of the sample points. Several data sets of sample1567points sharing the same x-coordinates can be fitted at once by1568passing in a 2D-array that contains one dataset per column.1569deg : int or 1-D array_like1570Degree(s) of the fitting polynomials. If `deg` is a single integer,1571all terms up to and including the `deg`'th term are included in the1572fit. For NumPy versions >= 1.11.0 a list of integers specifying the1573degrees of the terms to include may be used instead.1574rcond : float, optional1575Relative condition number of the fit. Singular values smaller than1576this relative to the largest singular value will be ignored. The1577default value is len(x)*eps, where eps is the relative precision of1578the float type, about 2e-16 in most cases.1579full : bool, optional1580Switch determining nature of return value. When it is False (the1581default) just the coefficients are returned, when True diagnostic1582information from the singular value decomposition is also returned.1583w : array_like, shape (`M`,), optional1584Weights. If not None, the weight ``w[i]`` applies to the unsquared1585residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are1586chosen so that the errors of the products ``w[i]*y[i]`` all have the1587same variance. When using inverse-variance weighting, use1588``w[i] = 1/sigma(y[i])``. The default value is None.15891590.. versionadded:: 1.5.015911592Returns1593-------1594coef : ndarray, shape (M,) or (M, K)1595Chebyshev coefficients ordered from low to high. If `y` was 2-D,1596the coefficients for the data in column k of `y` are in column1597`k`.15981599[residuals, rank, singular_values, rcond] : list1600These values are only returned if ``full == True``16011602- residuals -- sum of squared residuals of the least squares fit1603- rank -- the numerical rank of the scaled Vandermonde matrix1604- singular_values -- singular values of the scaled Vandermonde matrix1605- rcond -- value of `rcond`.16061607For more details, see `numpy.linalg.lstsq`.16081609Warns1610-----1611RankWarning1612The rank of the coefficient matrix in the least-squares fit is1613deficient. The warning is only raised if ``full == False``. The1614warnings can be turned off by16151616>>> import warnings1617>>> warnings.simplefilter('ignore', np.RankWarning)16181619See Also1620--------1621numpy.polynomial.polynomial.polyfit1622numpy.polynomial.legendre.legfit1623numpy.polynomial.laguerre.lagfit1624numpy.polynomial.hermite.hermfit1625numpy.polynomial.hermite_e.hermefit1626chebval : Evaluates a Chebyshev series.1627chebvander : Vandermonde matrix of Chebyshev series.1628chebweight : Chebyshev weight function.1629numpy.linalg.lstsq : Computes a least-squares fit from the matrix.1630scipy.interpolate.UnivariateSpline : Computes spline fits.16311632Notes1633-----1634The solution is the coefficients of the Chebyshev series `p` that1635minimizes the sum of the weighted squared errors16361637.. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,16381639where :math:`w_j` are the weights. This problem is solved by setting up1640as the (typically) overdetermined matrix equation16411642.. math:: V(x) * c = w * y,16431644where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the1645coefficients to be solved for, `w` are the weights, and `y` are the1646observed values. This equation is then solved using the singular value1647decomposition of `V`.16481649If some of the singular values of `V` are so small that they are1650neglected, then a `RankWarning` will be issued. This means that the1651coefficient values may be poorly determined. Using a lower order fit1652will usually get rid of the warning. The `rcond` parameter can also be1653set to a value smaller than its default, but the resulting fit may be1654spurious and have large contributions from roundoff error.16551656Fits using Chebyshev series are usually better conditioned than fits1657using power series, but much can depend on the distribution of the1658sample points and the smoothness of the data. If the quality of the fit1659is inadequate splines may be a good alternative.16601661References1662----------1663.. [1] Wikipedia, "Curve fitting",1664https://en.wikipedia.org/wiki/Curve_fitting16651666Examples1667--------16681669"""1670return pu._fit(chebvander, x, y, deg, rcond, full, w)167116721673def chebcompanion(c):1674"""Return the scaled companion matrix of c.16751676The basis polynomials are scaled so that the companion matrix is1677symmetric when `c` is a Chebyshev basis polynomial. This provides1678better eigenvalue estimates than the unscaled case and for basis1679polynomials the eigenvalues are guaranteed to be real if1680`numpy.linalg.eigvalsh` is used to obtain them.16811682Parameters1683----------1684c : array_like16851-D array of Chebyshev series coefficients ordered from low to high1686degree.16871688Returns1689-------1690mat : ndarray1691Scaled companion matrix of dimensions (deg, deg).16921693Notes1694-----16951696.. versionadded:: 1.7.016971698"""1699# c is a trimmed copy1700[c] = pu.as_series([c])1701if len(c) < 2:1702raise ValueError('Series must have maximum degree of at least 1.')1703if len(c) == 2:1704return np.array([[-c[0]/c[1]]])17051706n = len(c) - 11707mat = np.zeros((n, n), dtype=c.dtype)1708scl = np.array([1.] + [np.sqrt(.5)]*(n-1))1709top = mat.reshape(-1)[1::n+1]1710bot = mat.reshape(-1)[n::n+1]1711top[0] = np.sqrt(.5)1712top[1:] = 1/21713bot[...] = top1714mat[:, -1] -= (c[:-1]/c[-1])*(scl/scl[-1])*.51715return mat171617171718def chebroots(c):1719"""1720Compute the roots of a Chebyshev series.17211722Return the roots (a.k.a. "zeros") of the polynomial17231724.. math:: p(x) = \\sum_i c[i] * T_i(x).17251726Parameters1727----------1728c : 1-D array_like17291-D array of coefficients.17301731Returns1732-------1733out : ndarray1734Array of the roots of the series. If all the roots are real,1735then `out` is also real, otherwise it is complex.17361737See Also1738--------1739numpy.polynomial.polynomial.polyroots1740numpy.polynomial.legendre.legroots1741numpy.polynomial.laguerre.lagroots1742numpy.polynomial.hermite.hermroots1743numpy.polynomial.hermite_e.hermeroots17441745Notes1746-----1747The root estimates are obtained as the eigenvalues of the companion1748matrix, Roots far from the origin of the complex plane may have large1749errors due to the numerical instability of the series for such1750values. Roots with multiplicity greater than 1 will also show larger1751errors as the value of the series near such points is relatively1752insensitive to errors in the roots. Isolated roots near the origin can1753be improved by a few iterations of Newton's method.17541755The Chebyshev series basis polynomials aren't powers of `x` so the1756results of this function may seem unintuitive.17571758Examples1759--------1760>>> import numpy.polynomial.chebyshev as cheb1761>>> cheb.chebroots((-1, 1,-1, 1)) # T3 - T2 + T1 - T0 has real roots1762array([ -5.00000000e-01, 2.60860684e-17, 1.00000000e+00]) # may vary17631764"""1765# c is a trimmed copy1766[c] = pu.as_series([c])1767if len(c) < 2:1768return np.array([], dtype=c.dtype)1769if len(c) == 2:1770return np.array([-c[0]/c[1]])17711772# rotated companion matrix reduces error1773m = chebcompanion(c)[::-1,::-1]1774r = la.eigvals(m)1775r.sort()1776return r177717781779def chebinterpolate(func, deg, args=()):1780"""Interpolate a function at the Chebyshev points of the first kind.17811782Returns the Chebyshev series that interpolates `func` at the Chebyshev1783points of the first kind in the interval [-1, 1]. The interpolating1784series tends to a minmax approximation to `func` with increasing `deg`1785if the function is continuous in the interval.17861787.. versionadded:: 1.14.017881789Parameters1790----------1791func : function1792The function to be approximated. It must be a function of a single1793variable of the form ``f(x, a, b, c...)``, where ``a, b, c...`` are1794extra arguments passed in the `args` parameter.1795deg : int1796Degree of the interpolating polynomial1797args : tuple, optional1798Extra arguments to be used in the function call. Default is no extra1799arguments.18001801Returns1802-------1803coef : ndarray, shape (deg + 1,)1804Chebyshev coefficients of the interpolating series ordered from low to1805high.18061807Examples1808--------1809>>> import numpy.polynomial.chebyshev as C1810>>> C.chebfromfunction(lambda x: np.tanh(x) + 0.5, 8)1811array([ 5.00000000e-01, 8.11675684e-01, -9.86864911e-17,1812-5.42457905e-02, -2.71387850e-16, 4.51658839e-03,18132.46716228e-17, -3.79694221e-04, -3.26899002e-16])18141815Notes1816-----18171818The Chebyshev polynomials used in the interpolation are orthogonal when1819sampled at the Chebyshev points of the first kind. If it is desired to1820constrain some of the coefficients they can simply be set to the desired1821value after the interpolation, no new interpolation or fit is needed. This1822is especially useful if it is known apriori that some of coefficients are1823zero. For instance, if the function is even then the coefficients of the1824terms of odd degree in the result can be set to zero.18251826"""1827deg = np.asarray(deg)18281829# check arguments.1830if deg.ndim > 0 or deg.dtype.kind not in 'iu' or deg.size == 0:1831raise TypeError("deg must be an int")1832if deg < 0:1833raise ValueError("expected deg >= 0")18341835order = deg + 11836xcheb = chebpts1(order)1837yfunc = func(xcheb, *args)1838m = chebvander(xcheb, deg)1839c = np.dot(m.T, yfunc)1840c[0] /= order1841c[1:] /= 0.5*order18421843return c184418451846def chebgauss(deg):1847"""1848Gauss-Chebyshev quadrature.18491850Computes the sample points and weights for Gauss-Chebyshev quadrature.1851These sample points and weights will correctly integrate polynomials of1852degree :math:`2*deg - 1` or less over the interval :math:`[-1, 1]` with1853the weight function :math:`f(x) = 1/\\sqrt{1 - x^2}`.18541855Parameters1856----------1857deg : int1858Number of sample points and weights. It must be >= 1.18591860Returns1861-------1862x : ndarray18631-D ndarray containing the sample points.1864y : ndarray18651-D ndarray containing the weights.18661867Notes1868-----18691870.. versionadded:: 1.7.018711872The results have only been tested up to degree 100, higher degrees may1873be problematic. For Gauss-Chebyshev there are closed form solutions for1874the sample points and weights. If n = `deg`, then18751876.. math:: x_i = \\cos(\\pi (2 i - 1) / (2 n))18771878.. math:: w_i = \\pi / n18791880"""1881ideg = pu._deprecate_as_int(deg, "deg")1882if ideg <= 0:1883raise ValueError("deg must be a positive integer")18841885x = np.cos(np.pi * np.arange(1, 2*ideg, 2) / (2.0*ideg))1886w = np.ones(ideg)*(np.pi/ideg)18871888return x, w188918901891def chebweight(x):1892"""1893The weight function of the Chebyshev polynomials.18941895The weight function is :math:`1/\\sqrt{1 - x^2}` and the interval of1896integration is :math:`[-1, 1]`. The Chebyshev polynomials are1897orthogonal, but not normalized, with respect to this weight function.18981899Parameters1900----------1901x : array_like1902Values at which the weight function will be computed.19031904Returns1905-------1906w : ndarray1907The weight function at `x`.19081909Notes1910-----19111912.. versionadded:: 1.7.019131914"""1915w = 1./(np.sqrt(1. + x) * np.sqrt(1. - x))1916return w191719181919def chebpts1(npts):1920"""1921Chebyshev points of the first kind.19221923The Chebyshev points of the first kind are the points ``cos(x)``,1924where ``x = [pi*(k + .5)/npts for k in range(npts)]``.19251926Parameters1927----------1928npts : int1929Number of sample points desired.19301931Returns1932-------1933pts : ndarray1934The Chebyshev points of the first kind.19351936See Also1937--------1938chebpts219391940Notes1941-----19421943.. versionadded:: 1.5.019441945"""1946_npts = int(npts)1947if _npts != npts:1948raise ValueError("npts must be integer")1949if _npts < 1:1950raise ValueError("npts must be >= 1")19511952x = 0.5 * np.pi / _npts * np.arange(-_npts+1, _npts+1, 2)1953return np.sin(x)195419551956def chebpts2(npts):1957"""1958Chebyshev points of the second kind.19591960The Chebyshev points of the second kind are the points ``cos(x)``,1961where ``x = [pi*k/(npts - 1) for k in range(npts)]``.19621963Parameters1964----------1965npts : int1966Number of sample points desired.19671968Returns1969-------1970pts : ndarray1971The Chebyshev points of the second kind.19721973Notes1974-----19751976.. versionadded:: 1.5.019771978"""1979_npts = int(npts)1980if _npts != npts:1981raise ValueError("npts must be integer")1982if _npts < 2:1983raise ValueError("npts must be >= 2")19841985x = np.linspace(-np.pi, 0, _npts)1986return np.cos(x)198719881989#1990# Chebyshev series class1991#19921993class Chebyshev(ABCPolyBase):1994"""A Chebyshev series class.19951996The Chebyshev class provides the standard Python numerical methods1997'+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the1998methods listed below.19992000Parameters2001----------2002coef : array_like2003Chebyshev coefficients in order of increasing degree, i.e.,2004``(1, 2, 3)`` gives ``1*T_0(x) + 2*T_1(x) + 3*T_2(x)``.2005domain : (2,) array_like, optional2006Domain to use. The interval ``[domain[0], domain[1]]`` is mapped2007to the interval ``[window[0], window[1]]`` by shifting and scaling.2008The default value is [-1, 1].2009window : (2,) array_like, optional2010Window, see `domain` for its use. The default value is [-1, 1].20112012.. versionadded:: 1.6.020132014"""2015# Virtual Functions2016_add = staticmethod(chebadd)2017_sub = staticmethod(chebsub)2018_mul = staticmethod(chebmul)2019_div = staticmethod(chebdiv)2020_pow = staticmethod(chebpow)2021_val = staticmethod(chebval)2022_int = staticmethod(chebint)2023_der = staticmethod(chebder)2024_fit = staticmethod(chebfit)2025_line = staticmethod(chebline)2026_roots = staticmethod(chebroots)2027_fromroots = staticmethod(chebfromroots)20282029@classmethod2030def interpolate(cls, func, deg, domain=None, args=()):2031"""Interpolate a function at the Chebyshev points of the first kind.20322033Returns the series that interpolates `func` at the Chebyshev points of2034the first kind scaled and shifted to the `domain`. The resulting series2035tends to a minmax approximation of `func` when the function is2036continuous in the domain.20372038.. versionadded:: 1.14.020392040Parameters2041----------2042func : function2043The function to be interpolated. It must be a function of a single2044variable of the form ``f(x, a, b, c...)``, where ``a, b, c...`` are2045extra arguments passed in the `args` parameter.2046deg : int2047Degree of the interpolating polynomial.2048domain : {None, [beg, end]}, optional2049Domain over which `func` is interpolated. The default is None, in2050which case the domain is [-1, 1].2051args : tuple, optional2052Extra arguments to be used in the function call. Default is no2053extra arguments.20542055Returns2056-------2057polynomial : Chebyshev instance2058Interpolating Chebyshev instance.20592060Notes2061-----2062See `numpy.polynomial.chebfromfunction` for more details.20632064"""2065if domain is None:2066domain = cls.domain2067xfunc = lambda x: func(pu.mapdomain(x, cls.window, domain), *args)2068coef = chebinterpolate(xfunc, deg)2069return cls(coef, domain=domain)20702071# Virtual properties2072domain = np.array(chebdomain)2073window = np.array(chebdomain)2074basis_name = 'T'207520762077