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