Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
legendre.py1604 linesDownload Raw Back to polynomial
1"""
2==================================================
3Legendre Series (:mod:`numpy.polynomial.legendre`)
4==================================================
5
6This module provides a number of objects (mostly functions) useful for
7dealing with Legendre series, including a `Legendre` class that
8encapsulates the usual arithmetic operations.  (General information
9on how this module represents and works with such polynomials is in the
10docstring for its "parent" sub-package, `numpy.polynomial`).
11
12Classes
13-------
14.. autosummary::
15   :toctree: generated/
16
17    Legendre
18
19Constants
20---------
21
22.. autosummary::
23   :toctree: generated/
24
25   legdomain
26   legzero
27   legone
28   legx
29
30Arithmetic
31----------
32
33.. autosummary::
34   :toctree: generated/
35
36   legadd
37   legsub
38   legmulx
39   legmul
40   legdiv
41   legpow
42   legval
43   legval2d
44   legval3d
45   leggrid2d
46   leggrid3d
47
48Calculus
49--------
50
51.. autosummary::
52   :toctree: generated/
53
54   legder
55   legint
56
57Misc Functions
58--------------
59
60.. autosummary::
61   :toctree: generated/
62
63   legfromroots
64   legroots
65   legvander
66   legvander2d
67   legvander3d
68   leggauss
69   legweight
70   legcompanion
71   legfit
72   legtrim
73   legline
74   leg2poly
75   poly2leg
76
77See also
78--------
79numpy.polynomial
80
81"""
82import numpy as np
83
84from . import polyutils as pu
85from ._polybase import ABCPolyBase
86
87__all__ = [
88    'legzero', 'legone', 'legx', 'legdomain', 'legline', 'legadd',
89    'legsub', 'legmulx', 'legmul', 'legdiv', 'legpow', 'legval', 'legder',
90    'legint', 'leg2poly', 'poly2leg', 'legfromroots', 'legvander',
91    'legfit', 'legtrim', 'legroots', 'Legendre', 'legval2d', 'legval3d',
92    'leggrid2d', 'leggrid3d', 'legvander2d', 'legvander3d', 'legcompanion',
93    'leggauss', 'legweight']
94
95legtrim = pu.trimcoef
96
97
98def poly2leg(pol):
99    """
100    Convert a polynomial to a Legendre series.
101
102    Convert an array representing the coefficients of a polynomial (relative
103    to the "standard" basis) ordered from lowest degree to highest, to an
104    array of the coefficients of the equivalent Legendre series, ordered
105    from lowest to highest degree.
106
107    Parameters
108    ----------
109    pol : array_like
110        1-D array containing the polynomial coefficients
111
112    Returns
113    -------
114    c : ndarray
115        1-D array containing the coefficients of the equivalent Legendre
116        series.
117
118    See Also
119    --------
120    leg2poly
121
122    Notes
123    -----
124    The easy way to do conversions between polynomial basis sets
125    is to use the convert method of a class instance.
126
127    Examples
128    --------
129    >>> import numpy as np
130    >>> from numpy import polynomial as P
131    >>> p = P.Polynomial(np.arange(4))
132    >>> p
133    Polynomial([0.,  1.,  2.,  3.], domain=[-1.,  1.], window=[-1.,  1.], ...
134    >>> c = P.Legendre(P.legendre.poly2leg(p.coef))
135    >>> c
136    Legendre([ 1.  ,  3.25,  1.  ,  0.75], domain=[-1,  1], window=[-1,  1]) # may vary
137
138    """
139    [pol] = pu.as_series([pol])
140    deg = len(pol) - 1
141    res = 0
142    for i in range(deg, -1, -1):
143        res = legadd(legmulx(res), pol[i])
144    return res
145
146
147def leg2poly(c):
148    """
149    Convert a Legendre series to a polynomial.
150
151    Convert an array representing the coefficients of a Legendre series,
152    ordered from lowest degree to highest, to an array of the coefficients
153    of the equivalent polynomial (relative to the "standard" basis) ordered
154    from lowest to highest degree.
155
156    Parameters
157    ----------
158    c : array_like
159        1-D array containing the Legendre series coefficients, ordered
160        from lowest order term to highest.
161
162    Returns
163    -------
164    pol : ndarray
165        1-D array containing the coefficients of the equivalent polynomial
166        (relative to the "standard" basis) ordered from lowest order term
167        to highest.
168
169    See Also
170    --------
171    poly2leg
172
173    Notes
174    -----
175    The easy way to do conversions between polynomial basis sets
176    is to use the convert method of a class instance.
177
178    Examples
179    --------
180    >>> from numpy import polynomial as P
181    >>> c = P.Legendre(range(4))
182    >>> c
183    Legendre([0., 1., 2., 3.], domain=[-1.,  1.], window=[-1.,  1.], symbol='x')
184    >>> p = c.convert(kind=P.Polynomial)
185    >>> p
186    Polynomial([-1. , -3.5,  3. ,  7.5], domain=[-1.,  1.], window=[-1., ...
187    >>> P.legendre.leg2poly(range(4))
188    array([-1. , -3.5,  3. ,  7.5])
189
190
191    """
192    from .polynomial import polyadd, polymulx, polysub
193
194    [c] = pu.as_series([c])
195    n = len(c)
196    if n < 3:
197        return c
198    else:
199        c0 = c[-2]
200        c1 = c[-1]
201        # i is the current degree of c1
202        for i in range(n - 1, 1, -1):
203            tmp = c0
204            c0 = polysub(c[i - 2], (c1 * (i - 1)) / i)
205            c1 = polyadd(tmp, (polymulx(c1) * (2 * i - 1)) / i)
206        return polyadd(c0, polymulx(c1))
207
208
209#
210# These are constant arrays are of integer type so as to be compatible
211# with the widest range of other types, such as Decimal.
212#
213
214# Legendre
215legdomain = np.array([-1., 1.])
216
217# Legendre coefficients representing zero.
218legzero = np.array([0])
219
220# Legendre coefficients representing one.
221legone = np.array([1])
222
223# Legendre coefficients representing the identity x.
224legx = np.array([0, 1])
225
226
227def legline(off, scl):
228    """
229    Legendre series whose graph is a straight line.
230
231
232
233    Parameters
234    ----------
235    off, scl : scalars
236        The specified line is given by ``off + scl*x``.
237
238    Returns
239    -------
240    y : ndarray
241        This module's representation of the Legendre series for
242        ``off + scl*x``.
243
244    See Also
245    --------
246    numpy.polynomial.polynomial.polyline
247    numpy.polynomial.chebyshev.chebline
248    numpy.polynomial.laguerre.lagline
249    numpy.polynomial.hermite.hermline
250    numpy.polynomial.hermite_e.hermeline
251
252    Examples
253    --------
254    >>> import numpy.polynomial.legendre as L
255    >>> L.legline(3,2)
256    array([3, 2])
257    >>> L.legval(-3, L.legline(3,2)) # should be -3
258    -3.0
259
260    """
261    if scl != 0:
262        return np.array([off, scl])
263    else:
264        return np.array([off])
265
266
267def legfromroots(roots):
268    """
269    Generate a Legendre series with given roots.
270
271    The function returns the coefficients of the polynomial
272
273    .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n),
274
275    in Legendre form, where the :math:`r_n` are the roots specified in `roots`.
276    If a zero has multiplicity n, then it must appear in `roots` n times.
277    For instance, if 2 is a root of multiplicity three and 3 is a root of
278    multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The
279    roots can appear in any order.
280
281    If the returned coefficients are `c`, then
282
283    .. math:: p(x) = c_0 + c_1 * L_1(x) + ... +  c_n * L_n(x)
284
285    The coefficient of the last term is not generally 1 for monic
286    polynomials in Legendre form.
287
288    Parameters
289    ----------
290    roots : array_like
291        Sequence containing the roots.
292
293    Returns
294    -------
295    out : ndarray
296        1-D array of coefficients.  If all roots are real then `out` is a
297        real array, if some of the roots are complex, then `out` is complex
298        even if all the coefficients in the result are real (see Examples
299        below).
300
301    See Also
302    --------
303    numpy.polynomial.polynomial.polyfromroots
304    numpy.polynomial.chebyshev.chebfromroots
305    numpy.polynomial.laguerre.lagfromroots
306    numpy.polynomial.hermite.hermfromroots
307    numpy.polynomial.hermite_e.hermefromroots
308
309    Examples
310    --------
311    >>> import numpy.polynomial.legendre as L
312    >>> L.legfromroots((-1,0,1)) # x^3 - x relative to the standard basis
313    array([ 0. , -0.4,  0. ,  0.4])
314    >>> j = complex(0,1)
315    >>> L.legfromroots((-j,j)) # x^2 + 1 relative to the standard basis
316    array([ 1.33333333+0.j,  0.00000000+0.j,  0.66666667+0.j]) # may vary
317
318    """
319    return pu._fromroots(legline, legmul, roots)
320
321
322def legadd(c1, c2):
323    """
324    Add one Legendre series to another.
325
326    Returns the sum of two Legendre series `c1` + `c2`.  The arguments
327    are sequences of coefficients ordered from lowest order term to
328    highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.
329
330    Parameters
331    ----------
332    c1, c2 : array_like
333        1-D arrays of Legendre series coefficients ordered from low to
334        high.
335
336    Returns
337    -------
338    out : ndarray
339        Array representing the Legendre series of their sum.
340
341    See Also
342    --------
343    legsub, legmulx, legmul, legdiv, legpow
344
345    Notes
346    -----
347    Unlike multiplication, division, etc., the sum of two Legendre series
348    is a Legendre series (without having to "reproject" the result onto
349    the basis set) so addition, just like that of "standard" polynomials,
350    is simply "component-wise."
351
352    Examples
353    --------
354    >>> from numpy.polynomial import legendre as L
355    >>> c1 = (1,2,3)
356    >>> c2 = (3,2,1)
357    >>> L.legadd(c1,c2)
358    array([4.,  4.,  4.])
359
360    """
361    return pu._add(c1, c2)
362
363
364def legsub(c1, c2):
365    """
366    Subtract one Legendre series from another.
367
368    Returns the difference of two Legendre series `c1` - `c2`.  The
369    sequences of coefficients are from lowest order term to highest, i.e.,
370    [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.
371
372    Parameters
373    ----------
374    c1, c2 : array_like
375        1-D arrays of Legendre series coefficients ordered from low to
376        high.
377
378    Returns
379    -------
380    out : ndarray
381        Of Legendre series coefficients representing their difference.
382
383    See Also
384    --------
385    legadd, legmulx, legmul, legdiv, legpow
386
387    Notes
388    -----
389    Unlike multiplication, division, etc., the difference of two Legendre
390    series is a Legendre series (without having to "reproject" the result
391    onto the basis set) so subtraction, just like that of "standard"
392    polynomials, is simply "component-wise."
393
394    Examples
395    --------
396    >>> from numpy.polynomial import legendre as L
397    >>> c1 = (1,2,3)
398    >>> c2 = (3,2,1)
399    >>> L.legsub(c1,c2)
400    array([-2.,  0.,  2.])
401    >>> L.legsub(c2,c1) # -C.legsub(c1,c2)
402    array([ 2.,  0., -2.])
403
404    """
405    return pu._sub(c1, c2)
406
407
408def legmulx(c):
409    """Multiply a Legendre series by x.
410
411    Multiply the Legendre series `c` by x, where x is the independent
412    variable.
413
414
415    Parameters
416    ----------
417    c : array_like
418        1-D array of Legendre series coefficients ordered from low to
419        high.
420
421    Returns
422    -------
423    out : ndarray
424        Array representing the result of the multiplication.
425
426    See Also
427    --------
428    legadd, legsub, legmul, legdiv, legpow
429
430    Notes
431    -----
432    The multiplication uses the recursion relationship for Legendre
433    polynomials in the form
434
435    .. math::
436
437      xP_i(x) = ((i + 1)*P_{i + 1}(x) + i*P_{i - 1}(x))/(2i + 1)
438
439    Examples
440    --------
441    >>> from numpy.polynomial import legendre as L
442    >>> L.legmulx([1,2,3])
443    array([ 0.66666667, 2.2, 1.33333333, 1.8]) # may vary
444
445    """
446    # c is a trimmed copy
447    [c] = pu.as_series([c])
448    # The zero series needs special treatment
449    if len(c) == 1 and c[0] == 0:
450        return c
451
452    prd = np.empty(len(c) + 1, dtype=c.dtype)
453    prd[0] = c[0] * 0
454    prd[1] = c[0]
455    for i in range(1, len(c)):
456        j = i + 1
457        k = i - 1
458        s = i + j
459        prd[j] = (c[i] * j) / s
460        prd[k] += (c[i] * i) / s
461    return prd
462
463
464def legmul(c1, c2):
465    """
466    Multiply one Legendre series by another.
467
468    Returns the product of two Legendre series `c1` * `c2`.  The arguments
469    are sequences of coefficients, from lowest order "term" to highest,
470    e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.
471
472    Parameters
473    ----------
474    c1, c2 : array_like
475        1-D arrays of Legendre series coefficients ordered from low to
476        high.
477
478    Returns
479    -------
480    out : ndarray
481        Of Legendre series coefficients representing their product.
482
483    See Also
484    --------
485    legadd, legsub, legmulx, legdiv, legpow
486
487    Notes
488    -----
489    In general, the (polynomial) product of two C-series results in terms
490    that are not in the Legendre polynomial basis set.  Thus, to express
491    the product as a Legendre series, it is necessary to "reproject" the
492    product onto said basis set, which may produce "unintuitive" (but
493    correct) results; see Examples section below.
494
495    Examples
496    --------
497    >>> from numpy.polynomial import legendre as L
498    >>> c1 = (1,2,3)
499    >>> c2 = (3,2)
500    >>> L.legmul(c1,c2) # multiplication requires "reprojection"
501    array([  4.33333333,  10.4       ,  11.66666667,   3.6       ]) # may vary
502
503    """
504    # s1, s2 are trimmed copies
505    [c1, c2] = pu.as_series([c1, c2])
506
507    if len(c1) > len(c2):
508        c = c2
509        xs = c1
510    else:
511        c = c1
512        xs = c2
513
514    if len(c) == 1:
515        c0 = c[0] * xs
516        c1 = 0
517    elif len(c) == 2:
518        c0 = c[0] * xs
519        c1 = c[1] * xs
520    else:
521        nd = len(c)
522        c0 = c[-2] * xs
523        c1 = c[-1] * xs
524        for i in range(3, len(c) + 1):
525            tmp = c0
526            nd = nd - 1
527            c0 = legsub(c[-i] * xs, (c1 * (nd - 1)) / nd)
528            c1 = legadd(tmp, (legmulx(c1) * (2 * nd - 1)) / nd)
529    return legadd(c0, legmulx(c1))
530
531
532def legdiv(c1, c2):
533    """
534    Divide one Legendre series by another.
535
536    Returns the quotient-with-remainder of two Legendre series
537    `c1` / `c2`.  The arguments are sequences of coefficients from lowest
538    order "term" to highest, e.g., [1,2,3] represents the series
539    ``P_0 + 2*P_1 + 3*P_2``.
540
541    Parameters
542    ----------
543    c1, c2 : array_like
544        1-D arrays of Legendre series coefficients ordered from low to
545        high.
546
547    Returns
548    -------
549    quo, rem : ndarrays
550        Of Legendre series coefficients representing the quotient and
551        remainder.
552
553    See Also
554    --------
555    legadd, legsub, legmulx, legmul, legpow
556
557    Notes
558    -----
559    In general, the (polynomial) division of one Legendre series by another
560    results in quotient and remainder terms that are not in the Legendre
561    polynomial basis set.  Thus, to express these results as a Legendre
562    series, it is necessary to "reproject" the results onto the Legendre
563    basis set, which may produce "unintuitive" (but correct) results; see
564    Examples section below.
565
566    Examples
567    --------
568    >>> from numpy.polynomial import legendre as L
569    >>> c1 = (1,2,3)
570    >>> c2 = (3,2,1)
571    >>> L.legdiv(c1,c2) # quotient "intuitive," remainder not
572    (array([3.]), array([-8., -4.]))
573    >>> c2 = (0,1,2,3)
574    >>> L.legdiv(c2,c1) # neither "intuitive"
575    (array([-0.07407407,  1.66666667]), array([-1.03703704, -2.51851852])) # may vary
576
577    """
578    return pu._div(legmul, c1, c2)
579
580
581def legpow(c, pow, maxpower=16):
582    """Raise a Legendre series to a power.
583
584    Returns the Legendre series `c` raised to the power `pow`. The
585    argument `c` is a sequence of coefficients ordered from low to high.
586    i.e., [1,2,3] is the series  ``P_0 + 2*P_1 + 3*P_2.``
587
588    Parameters
589    ----------
590    c : array_like
591        1-D array of Legendre series coefficients ordered from low to
592        high.
593    pow : integer
594        Power to which the series will be raised
595    maxpower : integer, optional
596        Maximum power allowed. This is mainly to limit growth of the series
597        to unmanageable size. Default is 16
598
599    Returns
600    -------
601    coef : ndarray
602        Legendre series of power.
603
604    See Also
605    --------
606    legadd, legsub, legmulx, legmul, legdiv
607
608    """
609    return pu._pow(legmul, c, pow, maxpower)
610
611
612def legder(c, m=1, scl=1, axis=0):
613    """
614    Differentiate a Legendre series.
615
616    Returns the Legendre series coefficients `c` differentiated `m` times
617    along `axis`.  At each iteration the result is multiplied by `scl` (the
618    scaling factor is for use in a linear change of variable). The argument
619    `c` is an array of coefficients from low to high degree along each
620    axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2``
621    while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) +
622    2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is
623    ``y``.
624
625    Parameters
626    ----------
627    c : array_like
628        Array of Legendre series coefficients. If c is multidimensional the
629        different axis correspond to different variables with the degree in
630        each axis given by the corresponding index.
631    m : int, optional
632        Number of derivatives taken, must be non-negative. (Default: 1)
633    scl : scalar, optional
634        Each differentiation is multiplied by `scl`.  The end result is
635        multiplication by ``scl**m``.  This is for use in a linear change of
636        variable. (Default: 1)
637    axis : int, optional
638        Axis over which the derivative is taken. (Default: 0).
639
640    Returns
641    -------
642    der : ndarray
643        Legendre series of the derivative.
644
645    See Also
646    --------
647    legint
648
649    Notes
650    -----
651    In general, the result of differentiating a Legendre series does not
652    resemble the same operation on a power series. Thus the result of this
653    function may be "unintuitive," albeit correct; see Examples section
654    below.
655
656    Examples
657    --------
658    >>> from numpy.polynomial import legendre as L
659    >>> c = (1,2,3,4)
660    >>> L.legder(c)
661    array([  6.,   9.,  20.])
662    >>> L.legder(c, 3)
663    array([60.])
664    >>> L.legder(c, scl=-1)
665    array([ -6.,  -9., -20.])
666    >>> L.legder(c, 2,-1)
667    array([  9.,  60.])
668
669    """
670    c = np.array(c, ndmin=1, copy=True)
671    if c.dtype.char in '?bBhHiIlLqQpP':
672        c = c.astype(np.double)
673    cnt = pu._as_int(m, "the order of derivation")
674    iaxis = pu._as_int(axis, "the axis")
675    if cnt < 0:
676        raise ValueError("The order of derivation must be non-negative")
677    iaxis = np.lib.array_utils.normalize_axis_index(iaxis, c.ndim)
678
679    if cnt == 0:
680        return c
681
682    c = np.moveaxis(c, iaxis, 0)
683    n = len(c)
684    if cnt >= n:
685        c = c[:1] * 0
686    else:
687        for i in range(cnt):
688            n = n - 1
689            c *= scl
690            der = np.empty((n,) + c.shape[1:], dtype=c.dtype)
691            for j in range(n, 2, -1):
692                der[j - 1] = (2 * j - 1) * c[j]
693                c[j - 2] += c[j]
694            if n > 1:
695                der[1] = 3 * c[2]
696            der[0] = c[1]
697            c = der
698    c = np.moveaxis(c, 0, iaxis)
699    return c
700
701
702def legint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
703    """
704    Integrate a Legendre series.
705
706    Returns the Legendre series coefficients `c` integrated `m` times from
707    `lbnd` along `axis`. At each iteration the resulting series is
708    **multiplied** by `scl` and an integration constant, `k`, is added.
709    The scaling factor is for use in a linear change of variable.  ("Buyer
710    beware": note that, depending on what one is doing, one may want `scl`
711    to be the reciprocal of what one might expect; for more information,
712    see the Notes section below.)  The argument `c` is an array of
713    coefficients from low to high degree along each axis, e.g., [1,2,3]
714    represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]]
715    represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) +
716    2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.
717
718    Parameters
719    ----------
720    c : array_like
721        Array of Legendre series coefficients. If c is multidimensional the
722        different axis correspond to different variables with the degree in
723        each axis given by the corresponding index.
724    m : int, optional
725        Order of integration, must be positive. (Default: 1)
726    k : {[], list, scalar}, optional
727        Integration constant(s).  The value of the first integral at
728        ``lbnd`` is the first value in the list, the value of the second
729        integral at ``lbnd`` is the second value, etc.  If ``k == []`` (the
730        default), all constants are set to zero.  If ``m == 1``, a single
731        scalar can be given instead of a list.
732    lbnd : scalar, optional
733        The lower bound of the integral. (Default: 0)
734    scl : scalar, optional
735        Following each integration the result is *multiplied* by `scl`
736        before the integration constant is added. (Default: 1)
737    axis : int, optional
738        Axis over which the integral is taken. (Default: 0).
739
740    Returns
741    -------
742    S : ndarray
743        Legendre series coefficient array of the integral.
744
745    Raises
746    ------
747    ValueError
748        If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or
749        ``np.ndim(scl) != 0``.
750
751    See Also
752    --------
753    legder
754
755    Notes
756    -----
757    Note that the result of each integration is *multiplied* by `scl`.
758    Why is this important to note?  Say one is making a linear change of
759    variable :math:`u = ax + b` in an integral relative to `x`.  Then
760    :math:`dx = du/a`, so one will need to set `scl` equal to
761    :math:`1/a` - perhaps not what one would have first thought.
762
763    Also note that, in general, the result of integrating a C-series needs
764    to be "reprojected" onto the C-series basis set.  Thus, typically,
765    the result of this function is "unintuitive," albeit correct; see
766    Examples section below.
767
768    Examples
769    --------
770    >>> from numpy.polynomial import legendre as L
771    >>> c = (1,2,3)
772    >>> L.legint(c)
773    array([ 0.33333333,  0.4       ,  0.66666667,  0.6       ]) # may vary
774    >>> L.legint(c, 3)
775    array([  1.66666667e-02,  -1.78571429e-02,   4.76190476e-02, # may vary
776             -1.73472348e-18,   1.90476190e-02,   9.52380952e-03])
777    >>> L.legint(c, k=3)
778     array([ 3.33333333,  0.4       ,  0.66666667,  0.6       ]) # may vary
779    >>> L.legint(c, lbnd=-2)
780    array([ 7.33333333,  0.4       ,  0.66666667,  0.6       ]) # may vary
781    >>> L.legint(c, scl=2)
782    array([ 0.66666667,  0.8       ,  1.33333333,  1.2       ]) # may vary
783
784    """
785    c = np.array(c, ndmin=1, copy=True)
786    if c.dtype.char in '?bBhHiIlLqQpP':
787        c = c.astype(np.double)
788    if not np.iterable(k):
789        k = [k]
790    cnt = pu._as_int(m, "the order of integration")
791    iaxis = pu._as_int(axis, "the axis")
792    if cnt < 0:
793        raise ValueError("The order of integration must be non-negative")
794    if len(k) > cnt:
795        raise ValueError("Too many integration constants")
796    if np.ndim(lbnd) != 0:
797        raise ValueError("lbnd must be a scalar.")
798    if np.ndim(scl) != 0:
799        raise ValueError("scl must be a scalar.")
800    iaxis = np.lib.array_utils.normalize_axis_index(iaxis, c.ndim)
801
802    if cnt == 0:
803        return c
804
805    c = np.moveaxis(c, iaxis, 0)
806    k = list(k) + [0] * (cnt - len(k))
807    for i in range(cnt):
808        n = len(c)
809        c *= scl
810        if n == 1 and np.all(c[0] == 0):
811            c[0] += k[i]
812        else:
813            tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)
814            tmp[0] = c[0] * 0
815            tmp[1] = c[0]
816            if n > 1:
817                tmp[2] = c[1] / 3
818            for j in range(2, n):
819                t = c[j] / (2 * j + 1)
820                tmp[j + 1] = t
821                tmp[j - 1] -= t
822            tmp[0] += k[i] - legval(lbnd, tmp)
823            c = tmp
824    c = np.moveaxis(c, 0, iaxis)
825    return c
826
827
828def legval(x, c, tensor=True):
829    """
830    Evaluate a Legendre series at points x.
831
832    If `c` is of length ``n + 1``, this function returns the value:
833
834    .. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x)
835
836    The parameter `x` is converted to an array only if it is a tuple or a
837    list, otherwise it is treated as a scalar. In either case, either `x`
838    or its elements must support multiplication and addition both with
839    themselves and with the elements of `c`.
840
841    If `c` is a 1-D array, then ``p(x)`` will have the same shape as `x`.  If
842    `c` is multidimensional, then the shape of the result depends on the
843    value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +
844    x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that
845    scalars have shape (,).
846
847    Trailing zeros in the coefficients will be used in the evaluation, so
848    they should be avoided if efficiency is a concern.
849
850    Parameters
851    ----------
852    x : array_like, compatible object
853        If `x` is a list or tuple, it is converted to an ndarray, otherwise
854        it is left unchanged and treated as a scalar. In either case, `x`
855        or its elements must support addition and multiplication with
856        themselves and with the elements of `c`.
857    c : array_like
858        Array of coefficients ordered so that the coefficients for terms of
859        degree n are contained in c[n]. If `c` is multidimensional the
860        remaining indices enumerate multiple polynomials. In the two
861        dimensional case the coefficients may be thought of as stored in
862        the columns of `c`.
863    tensor : boolean, optional
864        If True, the shape of the coefficient array is extended with ones
865        on the right, one for each dimension of `x`. Scalars have dimension 0
866        for this action. The result is that every column of coefficients in
867        `c` is evaluated for every element of `x`. If False, `x` is broadcast
868        over the columns of `c` for the evaluation.  This keyword is useful
869        when `c` is multidimensional. The default value is True.
870
871    Returns
872    -------
873    values : ndarray, algebra_like
874        The shape of the return value is described above.
875
876    See Also
877    --------
878    legval2d, leggrid2d, legval3d, leggrid3d
879
880    Notes
881    -----
882    The evaluation uses Clenshaw recursion, aka synthetic division.
883
884    """
885    c = np.array(c, ndmin=1, copy=None)
886    if c.dtype.char in '?bBhHiIlLqQpP':
887        c = c.astype(np.double)
888    if isinstance(x, (tuple, list)):
889        x = np.asarray(x)
890    if isinstance(x, np.ndarray) and tensor:
891        c = c.reshape(c.shape + (1,) * x.ndim)
892
893    if len(c) == 1:
894        c0 = c[0]
895        c1 = 0
896    elif len(c) == 2:
897        c0 = c[0]
898        c1 = c[1]
899    else:
900        nd = len(c)
901        c0 = c[-2]
902        c1 = c[-1]
903        for i in range(3, len(c) + 1):
904            tmp = c0
905            nd = nd - 1
906            c0 = c[-i] - c1 * ((nd - 1) / nd)
907            c1 = tmp + c1 * x * ((2 * nd - 1) / nd)
908    return c0 + c1 * x
909
910
911def legval2d(x, y, c):
912    """
913    Evaluate a 2-D Legendre series at points (x, y).
914
915    This function returns the values:
916
917    .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y)
918
919    The parameters `x` and `y` are converted to arrays only if they are
920    tuples or a lists, otherwise they are treated as a scalars and they
921    must have the same shape after conversion. In either case, either `x`
922    and `y` or their elements must support multiplication and addition both
923    with themselves and with the elements of `c`.
924
925    If `c` is a 1-D array a one is implicitly appended to its shape to make
926    it 2-D. The shape of the result will be c.shape[2:] + x.shape.
927
928    Parameters
929    ----------
930    x, y : array_like, compatible objects
931        The two dimensional series is evaluated at the points ``(x, y)``,
932        where `x` and `y` must have the same shape. If `x` or `y` is a list
933        or tuple, it is first converted to an ndarray, otherwise it is left
934        unchanged and if it isn't an ndarray it is treated as a scalar.
935    c : array_like
936        Array of coefficients ordered so that the coefficient of the term
937        of multi-degree i,j is contained in ``c[i,j]``. If `c` has
938        dimension greater than two the remaining indices enumerate multiple
939        sets of coefficients.
940
941    Returns
942    -------
943    values : ndarray, compatible object
944        The values of the two dimensional Legendre series at points formed
945        from pairs of corresponding values from `x` and `y`.
946
947    See Also
948    --------
949    legval, leggrid2d, legval3d, leggrid3d
950    """
951    return pu._valnd(legval, c, x, y)
952
953
954def leggrid2d(x, y, c):
955    """
956    Evaluate a 2-D Legendre series on the Cartesian product of x and y.
957
958    This function returns the values:
959
960    .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b)
961
962    where the points ``(a, b)`` consist of all pairs formed by taking
963    `a` from `x` and `b` from `y`. The resulting points form a grid with
964    `x` in the first dimension and `y` in the second.
965
966    The parameters `x` and `y` are converted to arrays only if they are
967    tuples or a lists, otherwise they are treated as a scalars. In either
968    case, either `x` and `y` or their elements must support multiplication
969    and addition both with themselves and with the elements of `c`.
970
971    If `c` has fewer than two dimensions, ones are implicitly appended to
972    its shape to make it 2-D. The shape of the result will be c.shape[2:] +
973    x.shape + y.shape.
974
975    Parameters
976    ----------
977    x, y : array_like, compatible objects
978        The two dimensional series is evaluated at the points in the
979        Cartesian product of `x` and `y`.  If `x` or `y` is a list or
980        tuple, it is first converted to an ndarray, otherwise it is left
981        unchanged and, if it isn't an ndarray, it is treated as a scalar.
982    c : array_like
983        Array of coefficients ordered so that the coefficient of the term of
984        multi-degree i,j is contained in ``c[i,j]``. If `c` has dimension
985        greater than two the remaining indices enumerate multiple sets of
986        coefficients.
987
988    Returns
989    -------
990    values : ndarray, compatible object
991        The values of the two dimensional Chebyshev series at points in the
992        Cartesian product of `x` and `y`.
993
994    See Also
995    --------
996    legval, legval2d, legval3d, leggrid3d
997    """
998    return pu._gridnd(legval, c, x, y)
999
1000
1001def legval3d(x, y, z, c):
1002    """
1003    Evaluate a 3-D Legendre series at points (x, y, z).
1004
1005    This function returns the values:
1006
1007    .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z)
1008
1009    The parameters `x`, `y`, and `z` are converted to arrays only if
1010    they are tuples or a lists, otherwise they are treated as a scalars and
1011    they must have the same shape after conversion. In either case, either
1012    `x`, `y`, and `z` or their elements must support multiplication and
1013    addition both with themselves and with the elements of `c`.
1014
1015    If `c` has fewer than 3 dimensions, ones are implicitly appended to its
1016    shape to make it 3-D. The shape of the result will be c.shape[3:] +
1017    x.shape.
1018
1019    Parameters
1020    ----------
1021    x, y, z : array_like, compatible object
1022        The three dimensional series is evaluated at the points
1023        ``(x, y, z)``, where `x`, `y`, and `z` must have the same shape.  If
1024        any of `x`, `y`, or `z` is a list or tuple, it is first converted
1025        to an ndarray, otherwise it is left unchanged and if it isn't an
1026        ndarray it is  treated as a scalar.
1027    c : array_like
1028        Array of coefficients ordered so that the coefficient of the term of
1029        multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension
1030        greater than 3 the remaining indices enumerate multiple sets of
1031        coefficients.
1032
1033    Returns
1034    -------
1035    values : ndarray, compatible object
1036        The values of the multidimensional polynomial on points formed with
1037        triples of corresponding values from `x`, `y`, and `z`.
1038
1039    See Also
1040    --------
1041    legval, legval2d, leggrid2d, leggrid3d
1042    """
1043    return pu._valnd(legval, c, x, y, z)
1044
1045
1046def leggrid3d(x, y, z, c):
1047    """
1048    Evaluate a 3-D Legendre series on the Cartesian product of x, y, and z.
1049
1050    This function returns the values:
1051
1052    .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c)
1053
1054    where the points ``(a, b, c)`` consist of all triples formed by taking
1055    `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form
1056    a grid with `x` in the first dimension, `y` in the second, and `z` in
1057    the third.
1058
1059    The parameters `x`, `y`, and `z` are converted to arrays only if they
1060    are tuples or a lists, otherwise they are treated as a scalars. In
1061    either case, either `x`, `y`, and `z` or their elements must support
1062    multiplication and addition both with themselves and with the elements
1063    of `c`.
1064
1065    If `c` has fewer than three dimensions, ones are implicitly appended to
1066    its shape to make it 3-D. The shape of the result will be c.shape[3:] +
1067    x.shape + y.shape + z.shape.
1068
1069    Parameters
1070    ----------
1071    x, y, z : array_like, compatible objects
1072        The three dimensional series is evaluated at the points in the
1073        Cartesian product of `x`, `y`, and `z`.  If `x`, `y`, or `z` is a
1074        list or tuple, it is first converted to an ndarray, otherwise it is
1075        left unchanged and, if it isn't an ndarray, it is treated as a
1076        scalar.
1077    c : array_like
1078        Array of coefficients ordered so that the coefficients for terms of
1079        degree i,j are contained in ``c[i,j]``. If `c` has dimension
1080        greater than two the remaining indices enumerate multiple sets of
1081        coefficients.
1082
1083    Returns
1084    -------
1085    values : ndarray, compatible object
1086        The values of the two dimensional polynomial at points in the Cartesian
1087        product of `x` and `y`.
1088
1089    See Also
1090    --------
1091    legval, legval2d, leggrid2d, legval3d
1092    """
1093    return pu._gridnd(legval, c, x, y, z)
1094
1095
1096def legvander(x, deg):
1097    """Pseudo-Vandermonde matrix of given degree.
1098
1099    Returns the pseudo-Vandermonde matrix of degree `deg` and sample points
1100    `x`. The pseudo-Vandermonde matrix is defined by
1101
1102    .. math:: V[..., i] = L_i(x)
1103
1104    where ``0 <= i <= deg``. The leading indices of `V` index the elements of
1105    `x` and the last index is the degree of the Legendre polynomial.
1106
1107    If `c` is a 1-D array of coefficients of length ``n + 1`` and `V` is the
1108    array ``V = legvander(x, n)``, then ``np.dot(V, c)`` and
1109    ``legval(x, c)`` are the same up to roundoff. This equivalence is
1110    useful both for least squares fitting and for the evaluation of a large
1111    number of Legendre series of the same degree and sample points.
1112
1113    Parameters
1114    ----------
1115    x : array_like
1116        Array of points. The dtype is converted to float64 or complex128
1117        depending on whether any of the elements are complex. If `x` is
1118        scalar it is converted to a 1-D array.
1119    deg : int
1120        Degree of the resulting matrix.
1121
1122    Returns
1123    -------
1124    vander : ndarray
1125        The pseudo-Vandermonde matrix. The shape of the returned matrix is
1126        ``x.shape + (deg + 1,)``, where The last index is the degree of the
1127        corresponding Legendre polynomial.  The dtype will be the same as
1128        the converted `x`.
1129
1130    """
1131    ideg = pu._as_int(deg, "deg")
1132    if ideg < 0:
1133        raise ValueError("deg must be non-negative")
1134
1135    x = np.array(x, copy=None, ndmin=1) + 0.0
1136    dims = (ideg + 1,) + x.shape
1137    dtyp = x.dtype
1138    v = np.empty(dims, dtype=dtyp)
1139    # Use forward recursion to generate the entries. This is not as accurate
1140    # as reverse recursion in this application but it is more efficient.
1141    v[0] = x * 0 + 1
1142    if ideg > 0:
1143        v[1] = x
1144        for i in range(2, ideg + 1):
1145            v[i] = (v[i - 1] * x * (2 * i - 1) - v[i - 2] * (i - 1)) / i
1146    return np.moveaxis(v, 0, -1)
1147
1148
1149def legvander2d(x, y, deg):
1150    """Pseudo-Vandermonde matrix of given degrees.
1151
1152    Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
1153    points ``(x, y)``. The pseudo-Vandermonde matrix is defined by
1154
1155    .. math:: V[..., (deg[1] + 1)*i + j] = L_i(x) * L_j(y),
1156
1157    where ``0 <= i <= deg[0]`` and ``0 <= j <= deg[1]``. The leading indices of
1158    `V` index the points ``(x, y)`` and the last index encodes the degrees of
1159    the Legendre polynomials.
1160
1161    If ``V = legvander2d(x, y, [xdeg, ydeg])``, then the columns of `V`
1162    correspond to the elements of a 2-D coefficient array `c` of shape
1163    (xdeg + 1, ydeg + 1) in the order
1164
1165    .. math:: c_{00}, c_{01}, c_{02}, ... , c_{10}, c_{11}, c_{12}, ...
1166
1167    and ``np.dot(V, c.flat)`` and ``legval2d(x, y, c)`` will be the same
1168    up to roundoff. This equivalence is useful both for least squares
1169    fitting and for the evaluation of a large number of 2-D Legendre
1170    series of the same degrees and sample points.
1171
1172    Parameters
1173    ----------
1174    x, y : array_like
1175        Arrays of point coordinates, all of the same shape. The dtypes
1176        will be converted to either float64 or complex128 depending on
1177        whether any of the elements are complex. Scalars are converted to
1178        1-D arrays.
1179    deg : list of ints
1180        List of maximum degrees of the form [x_deg, y_deg].
1181
1182    Returns
1183    -------
1184    vander2d : ndarray
1185        The shape of the returned matrix is ``x.shape + (order,)``, where
1186        :math:`order = (deg[0]+1)*(deg[1]+1)`.  The dtype will be the same
1187        as the converted `x` and `y`.
1188
1189    See Also
1190    --------
1191    legvander, legvander3d, legval2d, legval3d
1192    """
1193    return pu._vander_nd_flat((legvander, legvander), (x, y), deg)
1194
1195
1196def legvander3d(x, y, z, deg):
1197    """Pseudo-Vandermonde matrix of given degrees.
1198
1199    Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
1200    points ``(x, y, z)``. If `l`, `m`, `n` are the given degrees in `x`, `y`, `z`,

Showing the first 1,200 of 1604 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai