Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/numpy/polynomial/legendre.py
7771 views
"""1==================================================2Legendre Series (:mod:`numpy.polynomial.legendre`)3==================================================45This module provides a number of objects (mostly functions) useful for6dealing with Legendre series, including a `Legendre` 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-------13.. autosummary::14:toctree: generated/1516Legendre1718Constants19---------2021.. autosummary::22:toctree: generated/2324legdomain25legzero26legone27legx2829Arithmetic30----------3132.. autosummary::33:toctree: generated/3435legadd36legsub37legmulx38legmul39legdiv40legpow41legval42legval2d43legval3d44leggrid2d45leggrid3d4647Calculus48--------4950.. autosummary::51:toctree: generated/5253legder54legint5556Misc Functions57--------------5859.. autosummary::60:toctree: generated/6162legfromroots63legroots64legvander65legvander2d66legvander3d67leggauss68legweight69legcompanion70legfit71legtrim72legline73leg2poly74poly2leg7576See also77--------78numpy.polynomial7980"""81import numpy as np82import numpy.linalg as la83from numpy.core.multiarray import normalize_axis_index8485from . import polyutils as pu86from ._polybase import ABCPolyBase8788__all__ = [89'legzero', 'legone', 'legx', 'legdomain', 'legline', 'legadd',90'legsub', 'legmulx', 'legmul', 'legdiv', 'legpow', 'legval', 'legder',91'legint', 'leg2poly', 'poly2leg', 'legfromroots', 'legvander',92'legfit', 'legtrim', 'legroots', 'Legendre', 'legval2d', 'legval3d',93'leggrid2d', 'leggrid3d', 'legvander2d', 'legvander3d', 'legcompanion',94'leggauss', 'legweight']9596legtrim = pu.trimcoef979899def poly2leg(pol):100"""101Convert a polynomial to a Legendre series.102103Convert an array representing the coefficients of a polynomial (relative104to the "standard" basis) ordered from lowest degree to highest, to an105array of the coefficients of the equivalent Legendre series, ordered106from lowest to highest degree.107108Parameters109----------110pol : array_like1111-D array containing the polynomial coefficients112113Returns114-------115c : ndarray1161-D array containing the coefficients of the equivalent Legendre117series.118119See Also120--------121leg2poly122123Notes124-----125The easy way to do conversions between polynomial basis sets126is to use the convert method of a class instance.127128Examples129--------130>>> from numpy import polynomial as P131>>> p = P.Polynomial(np.arange(4))132>>> p133Polynomial([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])134>>> c = P.Legendre(P.legendre.poly2leg(p.coef))135>>> c136Legendre([ 1. , 3.25, 1. , 0.75], domain=[-1, 1], window=[-1, 1]) # may vary137138"""139[pol] = pu.as_series([pol])140deg = len(pol) - 1141res = 0142for i in range(deg, -1, -1):143res = legadd(legmulx(res), pol[i])144return res145146147def leg2poly(c):148"""149Convert a Legendre series to a polynomial.150151Convert an array representing the coefficients of a Legendre series,152ordered from lowest degree to highest, to an array of the coefficients153of the equivalent polynomial (relative to the "standard" basis) ordered154from lowest to highest degree.155156Parameters157----------158c : array_like1591-D array containing the Legendre series coefficients, ordered160from lowest order term to highest.161162Returns163-------164pol : ndarray1651-D array containing the coefficients of the equivalent polynomial166(relative to the "standard" basis) ordered from lowest order term167to highest.168169See Also170--------171poly2leg172173Notes174-----175The easy way to do conversions between polynomial basis sets176is to use the convert method of a class instance.177178Examples179--------180>>> from numpy import polynomial as P181>>> c = P.Legendre(range(4))182>>> c183Legendre([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])184>>> p = c.convert(kind=P.Polynomial)185>>> p186Polynomial([-1. , -3.5, 3. , 7.5], domain=[-1., 1.], window=[-1., 1.])187>>> P.leg2poly(range(4))188array([-1. , -3.5, 3. , 7.5])189190191"""192from .polynomial import polyadd, polysub, polymulx193194[c] = pu.as_series([c])195n = len(c)196if n < 3:197return c198else:199c0 = c[-2]200c1 = c[-1]201# i is the current degree of c1202for i in range(n - 1, 1, -1):203tmp = c0204c0 = polysub(c[i - 2], (c1*(i - 1))/i)205c1 = polyadd(tmp, (polymulx(c1)*(2*i - 1))/i)206return polyadd(c0, polymulx(c1))207208#209# These are constant arrays are of integer type so as to be compatible210# with the widest range of other types, such as Decimal.211#212213# Legendre214legdomain = np.array([-1, 1])215216# Legendre coefficients representing zero.217legzero = np.array([0])218219# Legendre coefficients representing one.220legone = np.array([1])221222# Legendre coefficients representing the identity x.223legx = np.array([0, 1])224225226def legline(off, scl):227"""228Legendre series whose graph is a straight line.229230231232Parameters233----------234off, scl : scalars235The specified line is given by ``off + scl*x``.236237Returns238-------239y : ndarray240This module's representation of the Legendre series for241``off + scl*x``.242243See Also244--------245numpy.polynomial.polynomial.polyline246numpy.polynomial.chebyshev.chebline247numpy.polynomial.laguerre.lagline248numpy.polynomial.hermite.hermline249numpy.polynomial.hermite_e.hermeline250251Examples252--------253>>> import numpy.polynomial.legendre as L254>>> L.legline(3,2)255array([3, 2])256>>> L.legval(-3, L.legline(3,2)) # should be -3257-3.0258259"""260if scl != 0:261return np.array([off, scl])262else:263return np.array([off])264265266def legfromroots(roots):267"""268Generate a Legendre series with given roots.269270The function returns the coefficients of the polynomial271272.. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n),273274in Legendre form, where the `r_n` are the roots specified in `roots`.275If a zero has multiplicity n, then it must appear in `roots` n times.276For instance, if 2 is a root of multiplicity three and 3 is a root of277multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The278roots can appear in any order.279280If the returned coefficients are `c`, then281282.. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x)283284The coefficient of the last term is not generally 1 for monic285polynomials in Legendre form.286287Parameters288----------289roots : array_like290Sequence containing the roots.291292Returns293-------294out : ndarray2951-D array of coefficients. If all roots are real then `out` is a296real array, if some of the roots are complex, then `out` is complex297even if all the coefficients in the result are real (see Examples298below).299300See Also301--------302numpy.polynomial.polynomial.polyfromroots303numpy.polynomial.chebyshev.chebfromroots304numpy.polynomial.laguerre.lagfromroots305numpy.polynomial.hermite.hermfromroots306numpy.polynomial.hermite_e.hermefromroots307308Examples309--------310>>> import numpy.polynomial.legendre as L311>>> L.legfromroots((-1,0,1)) # x^3 - x relative to the standard basis312array([ 0. , -0.4, 0. , 0.4])313>>> j = complex(0,1)314>>> L.legfromroots((-j,j)) # x^2 + 1 relative to the standard basis315array([ 1.33333333+0.j, 0.00000000+0.j, 0.66666667+0.j]) # may vary316317"""318return pu._fromroots(legline, legmul, roots)319320321def legadd(c1, c2):322"""323Add one Legendre series to another.324325Returns the sum of two Legendre series `c1` + `c2`. The arguments326are sequences of coefficients ordered from lowest order term to327highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.328329Parameters330----------331c1, c2 : array_like3321-D arrays of Legendre series coefficients ordered from low to333high.334335Returns336-------337out : ndarray338Array representing the Legendre series of their sum.339340See Also341--------342legsub, legmulx, legmul, legdiv, legpow343344Notes345-----346Unlike multiplication, division, etc., the sum of two Legendre series347is a Legendre series (without having to "reproject" the result onto348the basis set) so addition, just like that of "standard" polynomials,349is simply "component-wise."350351Examples352--------353>>> from numpy.polynomial import legendre as L354>>> c1 = (1,2,3)355>>> c2 = (3,2,1)356>>> L.legadd(c1,c2)357array([4., 4., 4.])358359"""360return pu._add(c1, c2)361362363def legsub(c1, c2):364"""365Subtract one Legendre series from another.366367Returns the difference of two Legendre series `c1` - `c2`. The368sequences of coefficients are from lowest order term to highest, i.e.,369[1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.370371Parameters372----------373c1, c2 : array_like3741-D arrays of Legendre series coefficients ordered from low to375high.376377Returns378-------379out : ndarray380Of Legendre series coefficients representing their difference.381382See Also383--------384legadd, legmulx, legmul, legdiv, legpow385386Notes387-----388Unlike multiplication, division, etc., the difference of two Legendre389series is a Legendre series (without having to "reproject" the result390onto the basis set) so subtraction, just like that of "standard"391polynomials, is simply "component-wise."392393Examples394--------395>>> from numpy.polynomial import legendre as L396>>> c1 = (1,2,3)397>>> c2 = (3,2,1)398>>> L.legsub(c1,c2)399array([-2., 0., 2.])400>>> L.legsub(c2,c1) # -C.legsub(c1,c2)401array([ 2., 0., -2.])402403"""404return pu._sub(c1, c2)405406407def legmulx(c):408"""Multiply a Legendre series by x.409410Multiply the Legendre series `c` by x, where x is the independent411variable.412413414Parameters415----------416c : array_like4171-D array of Legendre series coefficients ordered from low to418high.419420Returns421-------422out : ndarray423Array representing the result of the multiplication.424425See Also426--------427legadd, legmul, legdiv, legpow428429Notes430-----431The multiplication uses the recursion relationship for Legendre432polynomials in the form433434.. math::435436xP_i(x) = ((i + 1)*P_{i + 1}(x) + i*P_{i - 1}(x))/(2i + 1)437438Examples439--------440>>> from numpy.polynomial import legendre as L441>>> L.legmulx([1,2,3])442array([ 0.66666667, 2.2, 1.33333333, 1.8]) # may vary443444"""445# c is a trimmed copy446[c] = pu.as_series([c])447# The zero series needs special treatment448if len(c) == 1 and c[0] == 0:449return c450451prd = np.empty(len(c) + 1, dtype=c.dtype)452prd[0] = c[0]*0453prd[1] = c[0]454for i in range(1, len(c)):455j = i + 1456k = i - 1457s = i + j458prd[j] = (c[i]*j)/s459prd[k] += (c[i]*i)/s460return prd461462463def legmul(c1, c2):464"""465Multiply one Legendre series by another.466467Returns the product of two Legendre series `c1` * `c2`. The arguments468are sequences of coefficients, from lowest order "term" to highest,469e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.470471Parameters472----------473c1, c2 : array_like4741-D arrays of Legendre series coefficients ordered from low to475high.476477Returns478-------479out : ndarray480Of Legendre series coefficients representing their product.481482See Also483--------484legadd, legsub, legmulx, legdiv, legpow485486Notes487-----488In general, the (polynomial) product of two C-series results in terms489that are not in the Legendre polynomial basis set. Thus, to express490the product as a Legendre series, it is necessary to "reproject" the491product onto said basis set, which may produce "unintuitive" (but492correct) results; see Examples section below.493494Examples495--------496>>> from numpy.polynomial import legendre as L497>>> c1 = (1,2,3)498>>> c2 = (3,2)499>>> L.legmul(c1,c2) # multiplication requires "reprojection"500array([ 4.33333333, 10.4 , 11.66666667, 3.6 ]) # may vary501502"""503# s1, s2 are trimmed copies504[c1, c2] = pu.as_series([c1, c2])505506if len(c1) > len(c2):507c = c2508xs = c1509else:510c = c1511xs = c2512513if len(c) == 1:514c0 = c[0]*xs515c1 = 0516elif len(c) == 2:517c0 = c[0]*xs518c1 = c[1]*xs519else:520nd = len(c)521c0 = c[-2]*xs522c1 = c[-1]*xs523for i in range(3, len(c) + 1):524tmp = c0525nd = nd - 1526c0 = legsub(c[-i]*xs, (c1*(nd - 1))/nd)527c1 = legadd(tmp, (legmulx(c1)*(2*nd - 1))/nd)528return legadd(c0, legmulx(c1))529530531def legdiv(c1, c2):532"""533Divide one Legendre series by another.534535Returns the quotient-with-remainder of two Legendre series536`c1` / `c2`. The arguments are sequences of coefficients from lowest537order "term" to highest, e.g., [1,2,3] represents the series538``P_0 + 2*P_1 + 3*P_2``.539540Parameters541----------542c1, c2 : array_like5431-D arrays of Legendre series coefficients ordered from low to544high.545546Returns547-------548quo, rem : ndarrays549Of Legendre series coefficients representing the quotient and550remainder.551552See Also553--------554legadd, legsub, legmulx, legmul, legpow555556Notes557-----558In general, the (polynomial) division of one Legendre series by another559results in quotient and remainder terms that are not in the Legendre560polynomial basis set. Thus, to express these results as a Legendre561series, it is necessary to "reproject" the results onto the Legendre562basis set, which may produce "unintuitive" (but correct) results; see563Examples section below.564565Examples566--------567>>> from numpy.polynomial import legendre as L568>>> c1 = (1,2,3)569>>> c2 = (3,2,1)570>>> L.legdiv(c1,c2) # quotient "intuitive," remainder not571(array([3.]), array([-8., -4.]))572>>> c2 = (0,1,2,3)573>>> L.legdiv(c2,c1) # neither "intuitive"574(array([-0.07407407, 1.66666667]), array([-1.03703704, -2.51851852])) # may vary575576"""577return pu._div(legmul, c1, c2)578579580def legpow(c, pow, maxpower=16):581"""Raise a Legendre series to a power.582583Returns the Legendre series `c` raised to the power `pow`. The584argument `c` is a sequence of coefficients ordered from low to high.585i.e., [1,2,3] is the series ``P_0 + 2*P_1 + 3*P_2.``586587Parameters588----------589c : array_like5901-D array of Legendre series coefficients ordered from low to591high.592pow : integer593Power to which the series will be raised594maxpower : integer, optional595Maximum power allowed. This is mainly to limit growth of the series596to unmanageable size. Default is 16597598Returns599-------600coef : ndarray601Legendre series of power.602603See Also604--------605legadd, legsub, legmulx, legmul, legdiv606607"""608return pu._pow(legmul, c, pow, maxpower)609610611def legder(c, m=1, scl=1, axis=0):612"""613Differentiate a Legendre series.614615Returns the Legendre series coefficients `c` differentiated `m` times616along `axis`. At each iteration the result is multiplied by `scl` (the617scaling factor is for use in a linear change of variable). The argument618`c` is an array of coefficients from low to high degree along each619axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2``620while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) +6212*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is622``y``.623624Parameters625----------626c : array_like627Array of Legendre series coefficients. If c is multidimensional the628different axis correspond to different variables with the degree in629each axis given by the corresponding index.630m : int, optional631Number of derivatives taken, must be non-negative. (Default: 1)632scl : scalar, optional633Each differentiation is multiplied by `scl`. The end result is634multiplication by ``scl**m``. This is for use in a linear change of635variable. (Default: 1)636axis : int, optional637Axis over which the derivative is taken. (Default: 0).638639.. versionadded:: 1.7.0640641Returns642-------643der : ndarray644Legendre series of the derivative.645646See Also647--------648legint649650Notes651-----652In general, the result of differentiating a Legendre series does not653resemble the same operation on a power series. Thus the result of this654function may be "unintuitive," albeit correct; see Examples section655below.656657Examples658--------659>>> from numpy.polynomial import legendre as L660>>> c = (1,2,3,4)661>>> L.legder(c)662array([ 6., 9., 20.])663>>> L.legder(c, 3)664array([60.])665>>> L.legder(c, scl=-1)666array([ -6., -9., -20.])667>>> L.legder(c, 2,-1)668array([ 9., 60.])669670"""671c = np.array(c, ndmin=1, copy=True)672if c.dtype.char in '?bBhHiIlLqQpP':673c = c.astype(np.double)674cnt = pu._deprecate_as_int(m, "the order of derivation")675iaxis = pu._deprecate_as_int(axis, "the axis")676if cnt < 0:677raise ValueError("The order of derivation must be non-negative")678iaxis = normalize_axis_index(iaxis, c.ndim)679680if cnt == 0:681return c682683c = np.moveaxis(c, iaxis, 0)684n = len(c)685if cnt >= n:686c = c[:1]*0687else:688for i in range(cnt):689n = n - 1690c *= scl691der = np.empty((n,) + c.shape[1:], dtype=c.dtype)692for j in range(n, 2, -1):693der[j - 1] = (2*j - 1)*c[j]694c[j - 2] += c[j]695if n > 1:696der[1] = 3*c[2]697der[0] = c[1]698c = der699c = np.moveaxis(c, 0, iaxis)700return c701702703def legint(c, m=1, k=[], lbnd=0, scl=1, axis=0):704"""705Integrate a Legendre series.706707Returns the Legendre series coefficients `c` integrated `m` times from708`lbnd` along `axis`. At each iteration the resulting series is709**multiplied** by `scl` and an integration constant, `k`, is added.710The scaling factor is for use in a linear change of variable. ("Buyer711beware": note that, depending on what one is doing, one may want `scl`712to be the reciprocal of what one might expect; for more information,713see the Notes section below.) The argument `c` is an array of714coefficients from low to high degree along each axis, e.g., [1,2,3]715represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]]716represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) +7172*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.718719Parameters720----------721c : array_like722Array of Legendre series coefficients. If c is multidimensional the723different axis correspond to different variables with the degree in724each axis given by the corresponding index.725m : int, optional726Order of integration, must be positive. (Default: 1)727k : {[], list, scalar}, optional728Integration constant(s). The value of the first integral at729``lbnd`` is the first value in the list, the value of the second730integral at ``lbnd`` is the second value, etc. If ``k == []`` (the731default), all constants are set to zero. If ``m == 1``, a single732scalar can be given instead of a list.733lbnd : scalar, optional734The lower bound of the integral. (Default: 0)735scl : scalar, optional736Following each integration the result is *multiplied* by `scl`737before the integration constant is added. (Default: 1)738axis : int, optional739Axis over which the integral is taken. (Default: 0).740741.. versionadded:: 1.7.0742743Returns744-------745S : ndarray746Legendre series coefficient array of the integral.747748Raises749------750ValueError751If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or752``np.ndim(scl) != 0``.753754See Also755--------756legder757758Notes759-----760Note that the result of each integration is *multiplied* by `scl`.761Why is this important to note? Say one is making a linear change of762variable :math:`u = ax + b` in an integral relative to `x`. Then763:math:`dx = du/a`, so one will need to set `scl` equal to764:math:`1/a` - perhaps not what one would have first thought.765766Also note that, in general, the result of integrating a C-series needs767to be "reprojected" onto the C-series basis set. Thus, typically,768the result of this function is "unintuitive," albeit correct; see769Examples section below.770771Examples772--------773>>> from numpy.polynomial import legendre as L774>>> c = (1,2,3)775>>> L.legint(c)776array([ 0.33333333, 0.4 , 0.66666667, 0.6 ]) # may vary777>>> L.legint(c, 3)778array([ 1.66666667e-02, -1.78571429e-02, 4.76190476e-02, # may vary779-1.73472348e-18, 1.90476190e-02, 9.52380952e-03])780>>> L.legint(c, k=3)781array([ 3.33333333, 0.4 , 0.66666667, 0.6 ]) # may vary782>>> L.legint(c, lbnd=-2)783array([ 7.33333333, 0.4 , 0.66666667, 0.6 ]) # may vary784>>> L.legint(c, scl=2)785array([ 0.66666667, 0.8 , 1.33333333, 1.2 ]) # may vary786787"""788c = np.array(c, ndmin=1, copy=True)789if c.dtype.char in '?bBhHiIlLqQpP':790c = c.astype(np.double)791if not np.iterable(k):792k = [k]793cnt = pu._deprecate_as_int(m, "the order of integration")794iaxis = pu._deprecate_as_int(axis, "the axis")795if cnt < 0:796raise ValueError("The order of integration must be non-negative")797if len(k) > cnt:798raise ValueError("Too many integration constants")799if np.ndim(lbnd) != 0:800raise ValueError("lbnd must be a scalar.")801if np.ndim(scl) != 0:802raise ValueError("scl must be a scalar.")803iaxis = normalize_axis_index(iaxis, c.ndim)804805if cnt == 0:806return c807808c = np.moveaxis(c, iaxis, 0)809k = list(k) + [0]*(cnt - len(k))810for i in range(cnt):811n = len(c)812c *= scl813if n == 1 and np.all(c[0] == 0):814c[0] += k[i]815else:816tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)817tmp[0] = c[0]*0818tmp[1] = c[0]819if n > 1:820tmp[2] = c[1]/3821for j in range(2, n):822t = c[j]/(2*j + 1)823tmp[j + 1] = t824tmp[j - 1] -= t825tmp[0] += k[i] - legval(lbnd, tmp)826c = tmp827c = np.moveaxis(c, 0, iaxis)828return c829830831def legval(x, c, tensor=True):832"""833Evaluate a Legendre series at points x.834835If `c` is of length `n + 1`, this function returns the value:836837.. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x)838839The parameter `x` is converted to an array only if it is a tuple or a840list, otherwise it is treated as a scalar. In either case, either `x`841or its elements must support multiplication and addition both with842themselves and with the elements of `c`.843844If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If845`c` is multidimensional, then the shape of the result depends on the846value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +847x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that848scalars have shape (,).849850Trailing zeros in the coefficients will be used in the evaluation, so851they should be avoided if efficiency is a concern.852853Parameters854----------855x : array_like, compatible object856If `x` is a list or tuple, it is converted to an ndarray, otherwise857it is left unchanged and treated as a scalar. In either case, `x`858or its elements must support addition and multiplication with859with themselves and with the elements of `c`.860c : array_like861Array of coefficients ordered so that the coefficients for terms of862degree n are contained in c[n]. If `c` is multidimensional the863remaining indices enumerate multiple polynomials. In the two864dimensional case the coefficients may be thought of as stored in865the columns of `c`.866tensor : boolean, optional867If True, the shape of the coefficient array is extended with ones868on the right, one for each dimension of `x`. Scalars have dimension 0869for this action. The result is that every column of coefficients in870`c` is evaluated for every element of `x`. If False, `x` is broadcast871over the columns of `c` for the evaluation. This keyword is useful872when `c` is multidimensional. The default value is True.873874.. versionadded:: 1.7.0875876Returns877-------878values : ndarray, algebra_like879The shape of the return value is described above.880881See Also882--------883legval2d, leggrid2d, legval3d, leggrid3d884885Notes886-----887The evaluation uses Clenshaw recursion, aka synthetic division.888889"""890c = np.array(c, ndmin=1, copy=False)891if c.dtype.char in '?bBhHiIlLqQpP':892c = c.astype(np.double)893if isinstance(x, (tuple, list)):894x = np.asarray(x)895if isinstance(x, np.ndarray) and tensor:896c = c.reshape(c.shape + (1,)*x.ndim)897898if len(c) == 1:899c0 = c[0]900c1 = 0901elif len(c) == 2:902c0 = c[0]903c1 = c[1]904else:905nd = len(c)906c0 = c[-2]907c1 = c[-1]908for i in range(3, len(c) + 1):909tmp = c0910nd = nd - 1911c0 = c[-i] - (c1*(nd - 1))/nd912c1 = tmp + (c1*x*(2*nd - 1))/nd913return c0 + c1*x914915916def legval2d(x, y, c):917"""918Evaluate a 2-D Legendre series at points (x, y).919920This function returns the values:921922.. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y)923924The parameters `x` and `y` are converted to arrays only if they are925tuples or a lists, otherwise they are treated as a scalars and they926must have the same shape after conversion. In either case, either `x`927and `y` or their elements must support multiplication and addition both928with themselves and with the elements of `c`.929930If `c` is a 1-D array a one is implicitly appended to its shape to make931it 2-D. The shape of the result will be c.shape[2:] + x.shape.932933Parameters934----------935x, y : array_like, compatible objects936The two dimensional series is evaluated at the points `(x, y)`,937where `x` and `y` must have the same shape. If `x` or `y` is a list938or tuple, it is first converted to an ndarray, otherwise it is left939unchanged and if it isn't an ndarray it is treated as a scalar.940c : array_like941Array of coefficients ordered so that the coefficient of the term942of multi-degree i,j is contained in ``c[i,j]``. If `c` has943dimension greater than two the remaining indices enumerate multiple944sets of coefficients.945946Returns947-------948values : ndarray, compatible object949The values of the two dimensional Legendre series at points formed950from pairs of corresponding values from `x` and `y`.951952See Also953--------954legval, leggrid2d, legval3d, leggrid3d955956Notes957-----958959.. versionadded:: 1.7.0960961"""962return pu._valnd(legval, c, x, y)963964965def leggrid2d(x, y, c):966"""967Evaluate a 2-D Legendre series on the Cartesian product of x and y.968969This function returns the values:970971.. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b)972973where the points `(a, b)` consist of all pairs formed by taking974`a` from `x` and `b` from `y`. The resulting points form a grid with975`x` in the first dimension and `y` in the second.976977The parameters `x` and `y` are converted to arrays only if they are978tuples or a lists, otherwise they are treated as a scalars. In either979case, either `x` and `y` or their elements must support multiplication980and addition both with themselves and with the elements of `c`.981982If `c` has fewer than two dimensions, ones are implicitly appended to983its shape to make it 2-D. The shape of the result will be c.shape[2:] +984x.shape + y.shape.985986Parameters987----------988x, y : array_like, compatible objects989The two dimensional series is evaluated at the points in the990Cartesian product of `x` and `y`. If `x` or `y` is a list or991tuple, it is first converted to an ndarray, otherwise it is left992unchanged and, if it isn't an ndarray, it is treated as a scalar.993c : array_like994Array of coefficients ordered so that the coefficient of the term of995multi-degree i,j is contained in `c[i,j]`. If `c` has dimension996greater than two the remaining indices enumerate multiple sets of997coefficients.998999Returns1000-------1001values : ndarray, compatible object1002The values of the two dimensional Chebyshev series at points in the1003Cartesian product of `x` and `y`.10041005See Also1006--------1007legval, legval2d, legval3d, leggrid3d10081009Notes1010-----10111012.. versionadded:: 1.7.010131014"""1015return pu._gridnd(legval, c, x, y)101610171018def legval3d(x, y, z, c):1019"""1020Evaluate a 3-D Legendre series at points (x, y, z).10211022This function returns the values:10231024.. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z)10251026The parameters `x`, `y`, and `z` are converted to arrays only if1027they are tuples or a lists, otherwise they are treated as a scalars and1028they must have the same shape after conversion. In either case, either1029`x`, `y`, and `z` or their elements must support multiplication and1030addition both with themselves and with the elements of `c`.10311032If `c` has fewer than 3 dimensions, ones are implicitly appended to its1033shape to make it 3-D. The shape of the result will be c.shape[3:] +1034x.shape.10351036Parameters1037----------1038x, y, z : array_like, compatible object1039The three dimensional series is evaluated at the points1040`(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If1041any of `x`, `y`, or `z` is a list or tuple, it is first converted1042to an ndarray, otherwise it is left unchanged and if it isn't an1043ndarray it is treated as a scalar.1044c : array_like1045Array of coefficients ordered so that the coefficient of the term of1046multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension1047greater than 3 the remaining indices enumerate multiple sets of1048coefficients.10491050Returns1051-------1052values : ndarray, compatible object1053The values of the multidimensional polynomial on points formed with1054triples of corresponding values from `x`, `y`, and `z`.10551056See Also1057--------1058legval, legval2d, leggrid2d, leggrid3d10591060Notes1061-----10621063.. versionadded:: 1.7.010641065"""1066return pu._valnd(legval, c, x, y, z)106710681069def leggrid3d(x, y, z, c):1070"""1071Evaluate a 3-D Legendre series on the Cartesian product of x, y, and z.10721073This function returns the values:10741075.. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c)10761077where the points `(a, b, c)` consist of all triples formed by taking1078`a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form1079a grid with `x` in the first dimension, `y` in the second, and `z` in1080the third.10811082The parameters `x`, `y`, and `z` are converted to arrays only if they1083are tuples or a lists, otherwise they are treated as a scalars. In1084either case, either `x`, `y`, and `z` or their elements must support1085multiplication and addition both with themselves and with the elements1086of `c`.10871088If `c` has fewer than three dimensions, ones are implicitly appended to1089its shape to make it 3-D. The shape of the result will be c.shape[3:] +1090x.shape + y.shape + z.shape.10911092Parameters1093----------1094x, y, z : array_like, compatible objects1095The three dimensional series is evaluated at the points in the1096Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a1097list or tuple, it is first converted to an ndarray, otherwise it is1098left unchanged and, if it isn't an ndarray, it is treated as a1099scalar.1100c : array_like1101Array of coefficients ordered so that the coefficients for terms of1102degree i,j are contained in ``c[i,j]``. If `c` has dimension1103greater than two the remaining indices enumerate multiple sets of1104coefficients.11051106Returns1107-------1108values : ndarray, compatible object1109The values of the two dimensional polynomial at points in the Cartesian1110product of `x` and `y`.11111112See Also1113--------1114legval, legval2d, leggrid2d, legval3d11151116Notes1117-----11181119.. versionadded:: 1.7.011201121"""1122return pu._gridnd(legval, c, x, y, z)112311241125def legvander(x, deg):1126"""Pseudo-Vandermonde matrix of given degree.11271128Returns the pseudo-Vandermonde matrix of degree `deg` and sample points1129`x`. The pseudo-Vandermonde matrix is defined by11301131.. math:: V[..., i] = L_i(x)11321133where `0 <= i <= deg`. The leading indices of `V` index the elements of1134`x` and the last index is the degree of the Legendre polynomial.11351136If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the1137array ``V = legvander(x, n)``, then ``np.dot(V, c)`` and1138``legval(x, c)`` are the same up to roundoff. This equivalence is1139useful both for least squares fitting and for the evaluation of a large1140number of Legendre series of the same degree and sample points.11411142Parameters1143----------1144x : array_like1145Array of points. The dtype is converted to float64 or complex1281146depending on whether any of the elements are complex. If `x` is1147scalar it is converted to a 1-D array.1148deg : int1149Degree of the resulting matrix.11501151Returns1152-------1153vander : ndarray1154The pseudo-Vandermonde matrix. The shape of the returned matrix is1155``x.shape + (deg + 1,)``, where The last index is the degree of the1156corresponding Legendre polynomial. The dtype will be the same as1157the converted `x`.11581159"""1160ideg = pu._deprecate_as_int(deg, "deg")1161if ideg < 0:1162raise ValueError("deg must be non-negative")11631164x = np.array(x, copy=False, ndmin=1) + 0.01165dims = (ideg + 1,) + x.shape1166dtyp = x.dtype1167v = np.empty(dims, dtype=dtyp)1168# Use forward recursion to generate the entries. This is not as accurate1169# as reverse recursion in this application but it is more efficient.1170v[0] = x*0 + 11171if ideg > 0:1172v[1] = x1173for i in range(2, ideg + 1):1174v[i] = (v[i-1]*x*(2*i - 1) - v[i-2]*(i - 1))/i1175return np.moveaxis(v, 0, -1)117611771178def legvander2d(x, y, deg):1179"""Pseudo-Vandermonde matrix of given degrees.11801181Returns the pseudo-Vandermonde matrix of degrees `deg` and sample1182points `(x, y)`. The pseudo-Vandermonde matrix is defined by11831184.. math:: V[..., (deg[1] + 1)*i + j] = L_i(x) * L_j(y),11851186where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of1187`V` index the points `(x, y)` and the last index encodes the degrees of1188the Legendre polynomials.11891190If ``V = legvander2d(x, y, [xdeg, ydeg])``, then the columns of `V`1191correspond to the elements of a 2-D coefficient array `c` of shape1192(xdeg + 1, ydeg + 1) in the order11931194.. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ...11951196and ``np.dot(V, c.flat)`` and ``legval2d(x, y, c)`` will be the same1197up to roundoff. This equivalence is useful both for least squares1198fitting and for the evaluation of a large number of 2-D Legendre1199series of the same degrees and sample points.12001201Parameters1202----------1203x, y : array_like1204Arrays of point coordinates, all of the same shape. The dtypes1205will be converted to either float64 or complex128 depending on1206whether any of the elements are complex. Scalars are converted to12071-D arrays.1208deg : list of ints1209List of maximum degrees of the form [x_deg, y_deg].12101211Returns1212-------1213vander2d : ndarray1214The shape of the returned matrix is ``x.shape + (order,)``, where1215:math:`order = (deg[0]+1)*(deg[1]+1)`. The dtype will be the same1216as the converted `x` and `y`.12171218See Also1219--------1220legvander, legvander3d, legval2d, legval3d12211222Notes1223-----12241225.. versionadded:: 1.7.012261227"""1228return pu._vander_nd_flat((legvander, legvander), (x, y), deg)122912301231def legvander3d(x, y, z, deg):1232"""Pseudo-Vandermonde matrix of given degrees.12331234Returns the pseudo-Vandermonde matrix of degrees `deg` and sample1235points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`,1236then The pseudo-Vandermonde matrix is defined by12371238.. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = L_i(x)*L_j(y)*L_k(z),12391240where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading1241indices of `V` index the points `(x, y, z)` and the last index encodes1242the degrees of the Legendre polynomials.12431244If ``V = legvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns1245of `V` correspond to the elements of a 3-D coefficient array `c` of1246shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order12471248.. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...12491250and ``np.dot(V, c.flat)`` and ``legval3d(x, y, z, c)`` will be the1251same up to roundoff. This equivalence is useful both for least squares1252fitting and for the evaluation of a large number of 3-D Legendre1253series of the same degrees and sample points.12541255Parameters1256----------1257x, y, z : array_like1258Arrays of point coordinates, all of the same shape. The dtypes will1259be converted to either float64 or complex128 depending on whether1260any of the elements are complex. Scalars are converted to 1-D1261arrays.1262deg : list of ints1263List of maximum degrees of the form [x_deg, y_deg, z_deg].12641265Returns1266-------1267vander3d : ndarray1268The shape of the returned matrix is ``x.shape + (order,)``, where1269:math:`order = (deg[0]+1)*(deg[1]+1)*(deg[2]+1)`. The dtype will1270be the same as the converted `x`, `y`, and `z`.12711272See Also1273--------1274legvander, legvander3d, legval2d, legval3d12751276Notes1277-----12781279.. versionadded:: 1.7.012801281"""1282return pu._vander_nd_flat((legvander, legvander, legvander), (x, y, z), deg)128312841285def legfit(x, y, deg, rcond=None, full=False, w=None):1286"""1287Least squares fit of Legendre series to data.12881289Return the coefficients of a Legendre series of degree `deg` that is the1290least squares fit to the data values `y` given at points `x`. If `y` is12911-D the returned coefficients will also be 1-D. If `y` is 2-D multiple1292fits are done, one for each column of `y`, and the resulting1293coefficients are stored in the corresponding columns of a 2-D return.1294The fitted polynomial(s) are in the form12951296.. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x),12971298where `n` is `deg`.12991300Parameters1301----------1302x : array_like, shape (M,)1303x-coordinates of the M sample points ``(x[i], y[i])``.1304y : array_like, shape (M,) or (M, K)1305y-coordinates of the sample points. Several data sets of sample1306points sharing the same x-coordinates can be fitted at once by1307passing in a 2D-array that contains one dataset per column.1308deg : int or 1-D array_like1309Degree(s) of the fitting polynomials. If `deg` is a single integer1310all terms up to and including the `deg`'th term are included in the1311fit. For NumPy versions >= 1.11.0 a list of integers specifying the1312degrees of the terms to include may be used instead.1313rcond : float, optional1314Relative condition number of the fit. Singular values smaller than1315this relative to the largest singular value will be ignored. The1316default value is len(x)*eps, where eps is the relative precision of1317the float type, about 2e-16 in most cases.1318full : bool, optional1319Switch determining nature of return value. When it is False (the1320default) just the coefficients are returned, when True diagnostic1321information from the singular value decomposition is also returned.1322w : array_like, shape (`M`,), optional1323Weights. If not None, the weight ``w[i]`` applies to the unsquared1324residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are1325chosen so that the errors of the products ``w[i]*y[i]`` all have the1326same variance. When using inverse-variance weighting, use1327``w[i] = 1/sigma(y[i])``. The default value is None.13281329.. versionadded:: 1.5.013301331Returns1332-------1333coef : ndarray, shape (M,) or (M, K)1334Legendre coefficients ordered from low to high. If `y` was13352-D, the coefficients for the data in column k of `y` are in1336column `k`. If `deg` is specified as a list, coefficients for1337terms not included in the fit are set equal to zero in the1338returned `coef`.13391340[residuals, rank, singular_values, rcond] : list1341These values are only returned if ``full == True``13421343- residuals -- sum of squared residuals of the least squares fit1344- rank -- the numerical rank of the scaled Vandermonde matrix1345- singular_values -- singular values of the scaled Vandermonde matrix1346- rcond -- value of `rcond`.13471348For more details, see `numpy.linalg.lstsq`.13491350Warns1351-----1352RankWarning1353The rank of the coefficient matrix in the least-squares fit is1354deficient. The warning is only raised if ``full == False``. The1355warnings can be turned off by13561357>>> import warnings1358>>> warnings.simplefilter('ignore', np.RankWarning)13591360See Also1361--------1362numpy.polynomial.polynomial.polyfit1363numpy.polynomial.chebyshev.chebfit1364numpy.polynomial.laguerre.lagfit1365numpy.polynomial.hermite.hermfit1366numpy.polynomial.hermite_e.hermefit1367legval : Evaluates a Legendre series.1368legvander : Vandermonde matrix of Legendre series.1369legweight : Legendre weight function (= 1).1370numpy.linalg.lstsq : Computes a least-squares fit from the matrix.1371scipy.interpolate.UnivariateSpline : Computes spline fits.13721373Notes1374-----1375The solution is the coefficients of the Legendre series `p` that1376minimizes the sum of the weighted squared errors13771378.. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,13791380where :math:`w_j` are the weights. This problem is solved by setting up1381as the (typically) overdetermined matrix equation13821383.. math:: V(x) * c = w * y,13841385where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the1386coefficients to be solved for, `w` are the weights, and `y` are the1387observed values. This equation is then solved using the singular value1388decomposition of `V`.13891390If some of the singular values of `V` are so small that they are1391neglected, then a `RankWarning` will be issued. This means that the1392coefficient values may be poorly determined. Using a lower order fit1393will usually get rid of the warning. The `rcond` parameter can also be1394set to a value smaller than its default, but the resulting fit may be1395spurious and have large contributions from roundoff error.13961397Fits using Legendre series are usually better conditioned than fits1398using power series, but much can depend on the distribution of the1399sample points and the smoothness of the data. If the quality of the fit1400is inadequate splines may be a good alternative.14011402References1403----------1404.. [1] Wikipedia, "Curve fitting",1405https://en.wikipedia.org/wiki/Curve_fitting14061407Examples1408--------14091410"""1411return pu._fit(legvander, x, y, deg, rcond, full, w)141214131414def legcompanion(c):1415"""Return the scaled companion matrix of c.14161417The basis polynomials are scaled so that the companion matrix is1418symmetric when `c` is an Legendre basis polynomial. This provides1419better eigenvalue estimates than the unscaled case and for basis1420polynomials the eigenvalues are guaranteed to be real if1421`numpy.linalg.eigvalsh` is used to obtain them.14221423Parameters1424----------1425c : array_like14261-D array of Legendre series coefficients ordered from low to high1427degree.14281429Returns1430-------1431mat : ndarray1432Scaled companion matrix of dimensions (deg, deg).14331434Notes1435-----14361437.. versionadded:: 1.7.014381439"""1440# c is a trimmed copy1441[c] = pu.as_series([c])1442if len(c) < 2:1443raise ValueError('Series must have maximum degree of at least 1.')1444if len(c) == 2:1445return np.array([[-c[0]/c[1]]])14461447n = len(c) - 11448mat = np.zeros((n, n), dtype=c.dtype)1449scl = 1./np.sqrt(2*np.arange(n) + 1)1450top = mat.reshape(-1)[1::n+1]1451bot = mat.reshape(-1)[n::n+1]1452top[...] = np.arange(1, n)*scl[:n-1]*scl[1:n]1453bot[...] = top1454mat[:, -1] -= (c[:-1]/c[-1])*(scl/scl[-1])*(n/(2*n - 1))1455return mat145614571458def legroots(c):1459"""1460Compute the roots of a Legendre series.14611462Return the roots (a.k.a. "zeros") of the polynomial14631464.. math:: p(x) = \\sum_i c[i] * L_i(x).14651466Parameters1467----------1468c : 1-D array_like14691-D array of coefficients.14701471Returns1472-------1473out : ndarray1474Array of the roots of the series. If all the roots are real,1475then `out` is also real, otherwise it is complex.14761477See Also1478--------1479numpy.polynomial.polynomial.polyroots1480numpy.polynomial.chebyshev.chebroots1481numpy.polynomial.laguerre.lagroots1482numpy.polynomial.hermite.hermroots1483numpy.polynomial.hermite_e.hermeroots14841485Notes1486-----1487The root estimates are obtained as the eigenvalues of the companion1488matrix, Roots far from the origin of the complex plane may have large1489errors due to the numerical instability of the series for such values.1490Roots with multiplicity greater than 1 will also show larger errors as1491the value of the series near such points is relatively insensitive to1492errors in the roots. Isolated roots near the origin can be improved by1493a few iterations of Newton's method.14941495The Legendre series basis polynomials aren't powers of ``x`` so the1496results of this function may seem unintuitive.14971498Examples1499--------1500>>> import numpy.polynomial.legendre as leg1501>>> leg.legroots((1, 2, 3, 4)) # 4L_3 + 3L_2 + 2L_1 + 1L_0, all real roots1502array([-0.85099543, -0.11407192, 0.51506735]) # may vary15031504"""1505# c is a trimmed copy1506[c] = pu.as_series([c])1507if len(c) < 2:1508return np.array([], dtype=c.dtype)1509if len(c) == 2:1510return np.array([-c[0]/c[1]])15111512# rotated companion matrix reduces error1513m = legcompanion(c)[::-1,::-1]1514r = la.eigvals(m)1515r.sort()1516return r151715181519def leggauss(deg):1520"""1521Gauss-Legendre quadrature.15221523Computes the sample points and weights for Gauss-Legendre quadrature.1524These sample points and weights will correctly integrate polynomials of1525degree :math:`2*deg - 1` or less over the interval :math:`[-1, 1]` with1526the weight function :math:`f(x) = 1`.15271528Parameters1529----------1530deg : int1531Number of sample points and weights. It must be >= 1.15321533Returns1534-------1535x : ndarray15361-D ndarray containing the sample points.1537y : ndarray15381-D ndarray containing the weights.15391540Notes1541-----15421543.. versionadded:: 1.7.015441545The results have only been tested up to degree 100, higher degrees may1546be problematic. The weights are determined by using the fact that15471548.. math:: w_k = c / (L'_n(x_k) * L_{n-1}(x_k))15491550where :math:`c` is a constant independent of :math:`k` and :math:`x_k`1551is the k'th root of :math:`L_n`, and then scaling the results to get1552the right value when integrating 1.15531554"""1555ideg = pu._deprecate_as_int(deg, "deg")1556if ideg <= 0:1557raise ValueError("deg must be a positive integer")15581559# first approximation of roots. We use the fact that the companion1560# matrix is symmetric in this case in order to obtain better zeros.1561c = np.array([0]*deg + [1])1562m = legcompanion(c)1563x = la.eigvalsh(m)15641565# improve roots by one application of Newton1566dy = legval(x, c)1567df = legval(x, legder(c))1568x -= dy/df15691570# compute the weights. We scale the factor to avoid possible numerical1571# overflow.1572fm = legval(x, c[1:])1573fm /= np.abs(fm).max()1574df /= np.abs(df).max()1575w = 1/(fm * df)15761577# for Legendre we can also symmetrize1578w = (w + w[::-1])/21579x = (x - x[::-1])/215801581# scale w to get the right value1582w *= 2. / w.sum()15831584return x, w158515861587def legweight(x):1588"""1589Weight function of the Legendre polynomials.15901591The weight function is :math:`1` and the interval of integration is1592:math:`[-1, 1]`. The Legendre polynomials are orthogonal, but not1593normalized, with respect to this weight function.15941595Parameters1596----------1597x : array_like1598Values at which the weight function will be computed.15991600Returns1601-------1602w : ndarray1603The weight function at `x`.16041605Notes1606-----16071608.. versionadded:: 1.7.016091610"""1611w = x*0.0 + 1.01612return w16131614#1615# Legendre series class1616#16171618class Legendre(ABCPolyBase):1619"""A Legendre series class.16201621The Legendre class provides the standard Python numerical methods1622'+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the1623attributes and methods listed in the `ABCPolyBase` documentation.16241625Parameters1626----------1627coef : array_like1628Legendre coefficients in order of increasing degree, i.e.,1629``(1, 2, 3)`` gives ``1*P_0(x) + 2*P_1(x) + 3*P_2(x)``.1630domain : (2,) array_like, optional1631Domain to use. The interval ``[domain[0], domain[1]]`` is mapped1632to the interval ``[window[0], window[1]]`` by shifting and scaling.1633The default value is [-1, 1].1634window : (2,) array_like, optional1635Window, see `domain` for its use. The default value is [-1, 1].16361637.. versionadded:: 1.6.016381639"""1640# Virtual Functions1641_add = staticmethod(legadd)1642_sub = staticmethod(legsub)1643_mul = staticmethod(legmul)1644_div = staticmethod(legdiv)1645_pow = staticmethod(legpow)1646_val = staticmethod(legval)1647_int = staticmethod(legint)1648_der = staticmethod(legder)1649_fit = staticmethod(legfit)1650_line = staticmethod(legline)1651_roots = staticmethod(legroots)1652_fromroots = staticmethod(legfromroots)16531654# Virtual properties1655domain = np.array(legdomain)1656window = np.array(legdomain)1657basis_name = 'P'165816591660