Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/numpy/polynomial/legendre.py
7771 views
1
"""
2
==================================================
3
Legendre Series (:mod:`numpy.polynomial.legendre`)
4
==================================================
5
6
This module provides a number of objects (mostly functions) useful for
7
dealing with Legendre series, including a `Legendre` class that
8
encapsulates the usual arithmetic operations. (General information
9
on how this module represents and works with such polynomials is in the
10
docstring for its "parent" sub-package, `numpy.polynomial`).
11
12
Classes
13
-------
14
.. autosummary::
15
:toctree: generated/
16
17
Legendre
18
19
Constants
20
---------
21
22
.. autosummary::
23
:toctree: generated/
24
25
legdomain
26
legzero
27
legone
28
legx
29
30
Arithmetic
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
48
Calculus
49
--------
50
51
.. autosummary::
52
:toctree: generated/
53
54
legder
55
legint
56
57
Misc 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
77
See also
78
--------
79
numpy.polynomial
80
81
"""
82
import numpy as np
83
import numpy.linalg as la
84
from numpy.core.multiarray import normalize_axis_index
85
86
from . import polyutils as pu
87
from ._polybase import ABCPolyBase
88
89
__all__ = [
90
'legzero', 'legone', 'legx', 'legdomain', 'legline', 'legadd',
91
'legsub', 'legmulx', 'legmul', 'legdiv', 'legpow', 'legval', 'legder',
92
'legint', 'leg2poly', 'poly2leg', 'legfromroots', 'legvander',
93
'legfit', 'legtrim', 'legroots', 'Legendre', 'legval2d', 'legval3d',
94
'leggrid2d', 'leggrid3d', 'legvander2d', 'legvander3d', 'legcompanion',
95
'leggauss', 'legweight']
96
97
legtrim = pu.trimcoef
98
99
100
def poly2leg(pol):
101
"""
102
Convert a polynomial to a Legendre series.
103
104
Convert an array representing the coefficients of a polynomial (relative
105
to the "standard" basis) ordered from lowest degree to highest, to an
106
array of the coefficients of the equivalent Legendre series, ordered
107
from lowest to highest degree.
108
109
Parameters
110
----------
111
pol : array_like
112
1-D array containing the polynomial coefficients
113
114
Returns
115
-------
116
c : ndarray
117
1-D array containing the coefficients of the equivalent Legendre
118
series.
119
120
See Also
121
--------
122
leg2poly
123
124
Notes
125
-----
126
The easy way to do conversions between polynomial basis sets
127
is to use the convert method of a class instance.
128
129
Examples
130
--------
131
>>> from numpy import polynomial as P
132
>>> p = P.Polynomial(np.arange(4))
133
>>> p
134
Polynomial([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])
135
>>> c = P.Legendre(P.legendre.poly2leg(p.coef))
136
>>> c
137
Legendre([ 1. , 3.25, 1. , 0.75], domain=[-1, 1], window=[-1, 1]) # may vary
138
139
"""
140
[pol] = pu.as_series([pol])
141
deg = len(pol) - 1
142
res = 0
143
for i in range(deg, -1, -1):
144
res = legadd(legmulx(res), pol[i])
145
return res
146
147
148
def leg2poly(c):
149
"""
150
Convert a Legendre series to a polynomial.
151
152
Convert an array representing the coefficients of a Legendre series,
153
ordered from lowest degree to highest, to an array of the coefficients
154
of the equivalent polynomial (relative to the "standard" basis) ordered
155
from lowest to highest degree.
156
157
Parameters
158
----------
159
c : array_like
160
1-D array containing the Legendre series coefficients, ordered
161
from lowest order term to highest.
162
163
Returns
164
-------
165
pol : ndarray
166
1-D array containing the coefficients of the equivalent polynomial
167
(relative to the "standard" basis) ordered from lowest order term
168
to highest.
169
170
See Also
171
--------
172
poly2leg
173
174
Notes
175
-----
176
The easy way to do conversions between polynomial basis sets
177
is to use the convert method of a class instance.
178
179
Examples
180
--------
181
>>> from numpy import polynomial as P
182
>>> c = P.Legendre(range(4))
183
>>> c
184
Legendre([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])
185
>>> p = c.convert(kind=P.Polynomial)
186
>>> p
187
Polynomial([-1. , -3.5, 3. , 7.5], domain=[-1., 1.], window=[-1., 1.])
188
>>> P.leg2poly(range(4))
189
array([-1. , -3.5, 3. , 7.5])
190
191
192
"""
193
from .polynomial import polyadd, polysub, polymulx
194
195
[c] = pu.as_series([c])
196
n = len(c)
197
if n < 3:
198
return c
199
else:
200
c0 = c[-2]
201
c1 = c[-1]
202
# i is the current degree of c1
203
for i in range(n - 1, 1, -1):
204
tmp = c0
205
c0 = polysub(c[i - 2], (c1*(i - 1))/i)
206
c1 = polyadd(tmp, (polymulx(c1)*(2*i - 1))/i)
207
return polyadd(c0, polymulx(c1))
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
215
legdomain = np.array([-1, 1])
216
217
# Legendre coefficients representing zero.
218
legzero = np.array([0])
219
220
# Legendre coefficients representing one.
221
legone = np.array([1])
222
223
# Legendre coefficients representing the identity x.
224
legx = np.array([0, 1])
225
226
227
def 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
267
def 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 `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
322
def 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
364
def 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
408
def 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, 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
464
def 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
532
def 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
581
def 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
612
def 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
.. versionadded:: 1.7.0
641
642
Returns
643
-------
644
der : ndarray
645
Legendre series of the derivative.
646
647
See Also
648
--------
649
legint
650
651
Notes
652
-----
653
In general, the result of differentiating a Legendre series does not
654
resemble the same operation on a power series. Thus the result of this
655
function may be "unintuitive," albeit correct; see Examples section
656
below.
657
658
Examples
659
--------
660
>>> from numpy.polynomial import legendre as L
661
>>> c = (1,2,3,4)
662
>>> L.legder(c)
663
array([ 6., 9., 20.])
664
>>> L.legder(c, 3)
665
array([60.])
666
>>> L.legder(c, scl=-1)
667
array([ -6., -9., -20.])
668
>>> L.legder(c, 2,-1)
669
array([ 9., 60.])
670
671
"""
672
c = np.array(c, ndmin=1, copy=True)
673
if c.dtype.char in '?bBhHiIlLqQpP':
674
c = c.astype(np.double)
675
cnt = pu._deprecate_as_int(m, "the order of derivation")
676
iaxis = pu._deprecate_as_int(axis, "the axis")
677
if cnt < 0:
678
raise ValueError("The order of derivation must be non-negative")
679
iaxis = normalize_axis_index(iaxis, c.ndim)
680
681
if cnt == 0:
682
return c
683
684
c = np.moveaxis(c, iaxis, 0)
685
n = len(c)
686
if cnt >= n:
687
c = c[:1]*0
688
else:
689
for i in range(cnt):
690
n = n - 1
691
c *= scl
692
der = np.empty((n,) + c.shape[1:], dtype=c.dtype)
693
for j in range(n, 2, -1):
694
der[j - 1] = (2*j - 1)*c[j]
695
c[j - 2] += c[j]
696
if n > 1:
697
der[1] = 3*c[2]
698
der[0] = c[1]
699
c = der
700
c = np.moveaxis(c, 0, iaxis)
701
return c
702
703
704
def legint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
705
"""
706
Integrate a Legendre series.
707
708
Returns the Legendre series coefficients `c` integrated `m` times from
709
`lbnd` along `axis`. At each iteration the resulting series is
710
**multiplied** by `scl` and an integration constant, `k`, is added.
711
The scaling factor is for use in a linear change of variable. ("Buyer
712
beware": note that, depending on what one is doing, one may want `scl`
713
to be the reciprocal of what one might expect; for more information,
714
see the Notes section below.) The argument `c` is an array of
715
coefficients from low to high degree along each axis, e.g., [1,2,3]
716
represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]]
717
represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) +
718
2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.
719
720
Parameters
721
----------
722
c : array_like
723
Array of Legendre series coefficients. If c is multidimensional the
724
different axis correspond to different variables with the degree in
725
each axis given by the corresponding index.
726
m : int, optional
727
Order of integration, must be positive. (Default: 1)
728
k : {[], list, scalar}, optional
729
Integration constant(s). The value of the first integral at
730
``lbnd`` is the first value in the list, the value of the second
731
integral at ``lbnd`` is the second value, etc. If ``k == []`` (the
732
default), all constants are set to zero. If ``m == 1``, a single
733
scalar can be given instead of a list.
734
lbnd : scalar, optional
735
The lower bound of the integral. (Default: 0)
736
scl : scalar, optional
737
Following each integration the result is *multiplied* by `scl`
738
before the integration constant is added. (Default: 1)
739
axis : int, optional
740
Axis over which the integral is taken. (Default: 0).
741
742
.. versionadded:: 1.7.0
743
744
Returns
745
-------
746
S : ndarray
747
Legendre series coefficient array of the integral.
748
749
Raises
750
------
751
ValueError
752
If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or
753
``np.ndim(scl) != 0``.
754
755
See Also
756
--------
757
legder
758
759
Notes
760
-----
761
Note that the result of each integration is *multiplied* by `scl`.
762
Why is this important to note? Say one is making a linear change of
763
variable :math:`u = ax + b` in an integral relative to `x`. Then
764
:math:`dx = du/a`, so one will need to set `scl` equal to
765
:math:`1/a` - perhaps not what one would have first thought.
766
767
Also note that, in general, the result of integrating a C-series needs
768
to be "reprojected" onto the C-series basis set. Thus, typically,
769
the result of this function is "unintuitive," albeit correct; see
770
Examples section below.
771
772
Examples
773
--------
774
>>> from numpy.polynomial import legendre as L
775
>>> c = (1,2,3)
776
>>> L.legint(c)
777
array([ 0.33333333, 0.4 , 0.66666667, 0.6 ]) # may vary
778
>>> L.legint(c, 3)
779
array([ 1.66666667e-02, -1.78571429e-02, 4.76190476e-02, # may vary
780
-1.73472348e-18, 1.90476190e-02, 9.52380952e-03])
781
>>> L.legint(c, k=3)
782
array([ 3.33333333, 0.4 , 0.66666667, 0.6 ]) # may vary
783
>>> L.legint(c, lbnd=-2)
784
array([ 7.33333333, 0.4 , 0.66666667, 0.6 ]) # may vary
785
>>> L.legint(c, scl=2)
786
array([ 0.66666667, 0.8 , 1.33333333, 1.2 ]) # may vary
787
788
"""
789
c = np.array(c, ndmin=1, copy=True)
790
if c.dtype.char in '?bBhHiIlLqQpP':
791
c = c.astype(np.double)
792
if not np.iterable(k):
793
k = [k]
794
cnt = pu._deprecate_as_int(m, "the order of integration")
795
iaxis = pu._deprecate_as_int(axis, "the axis")
796
if cnt < 0:
797
raise ValueError("The order of integration must be non-negative")
798
if len(k) > cnt:
799
raise ValueError("Too many integration constants")
800
if np.ndim(lbnd) != 0:
801
raise ValueError("lbnd must be a scalar.")
802
if np.ndim(scl) != 0:
803
raise ValueError("scl must be a scalar.")
804
iaxis = normalize_axis_index(iaxis, c.ndim)
805
806
if cnt == 0:
807
return c
808
809
c = np.moveaxis(c, iaxis, 0)
810
k = list(k) + [0]*(cnt - len(k))
811
for i in range(cnt):
812
n = len(c)
813
c *= scl
814
if n == 1 and np.all(c[0] == 0):
815
c[0] += k[i]
816
else:
817
tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)
818
tmp[0] = c[0]*0
819
tmp[1] = c[0]
820
if n > 1:
821
tmp[2] = c[1]/3
822
for j in range(2, n):
823
t = c[j]/(2*j + 1)
824
tmp[j + 1] = t
825
tmp[j - 1] -= t
826
tmp[0] += k[i] - legval(lbnd, tmp)
827
c = tmp
828
c = np.moveaxis(c, 0, iaxis)
829
return c
830
831
832
def legval(x, c, tensor=True):
833
"""
834
Evaluate a Legendre series at points x.
835
836
If `c` is of length `n + 1`, this function returns the value:
837
838
.. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x)
839
840
The parameter `x` is converted to an array only if it is a tuple or a
841
list, otherwise it is treated as a scalar. In either case, either `x`
842
or its elements must support multiplication and addition both with
843
themselves and with the elements of `c`.
844
845
If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If
846
`c` is multidimensional, then the shape of the result depends on the
847
value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +
848
x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that
849
scalars have shape (,).
850
851
Trailing zeros in the coefficients will be used in the evaluation, so
852
they should be avoided if efficiency is a concern.
853
854
Parameters
855
----------
856
x : array_like, compatible object
857
If `x` is a list or tuple, it is converted to an ndarray, otherwise
858
it is left unchanged and treated as a scalar. In either case, `x`
859
or its elements must support addition and multiplication with
860
with themselves and with the elements of `c`.
861
c : array_like
862
Array of coefficients ordered so that the coefficients for terms of
863
degree n are contained in c[n]. If `c` is multidimensional the
864
remaining indices enumerate multiple polynomials. In the two
865
dimensional case the coefficients may be thought of as stored in
866
the columns of `c`.
867
tensor : boolean, optional
868
If True, the shape of the coefficient array is extended with ones
869
on the right, one for each dimension of `x`. Scalars have dimension 0
870
for this action. The result is that every column of coefficients in
871
`c` is evaluated for every element of `x`. If False, `x` is broadcast
872
over the columns of `c` for the evaluation. This keyword is useful
873
when `c` is multidimensional. The default value is True.
874
875
.. versionadded:: 1.7.0
876
877
Returns
878
-------
879
values : ndarray, algebra_like
880
The shape of the return value is described above.
881
882
See Also
883
--------
884
legval2d, leggrid2d, legval3d, leggrid3d
885
886
Notes
887
-----
888
The evaluation uses Clenshaw recursion, aka synthetic division.
889
890
"""
891
c = np.array(c, ndmin=1, copy=False)
892
if c.dtype.char in '?bBhHiIlLqQpP':
893
c = c.astype(np.double)
894
if isinstance(x, (tuple, list)):
895
x = np.asarray(x)
896
if isinstance(x, np.ndarray) and tensor:
897
c = c.reshape(c.shape + (1,)*x.ndim)
898
899
if len(c) == 1:
900
c0 = c[0]
901
c1 = 0
902
elif len(c) == 2:
903
c0 = c[0]
904
c1 = c[1]
905
else:
906
nd = len(c)
907
c0 = c[-2]
908
c1 = c[-1]
909
for i in range(3, len(c) + 1):
910
tmp = c0
911
nd = nd - 1
912
c0 = c[-i] - (c1*(nd - 1))/nd
913
c1 = tmp + (c1*x*(2*nd - 1))/nd
914
return c0 + c1*x
915
916
917
def legval2d(x, y, c):
918
"""
919
Evaluate a 2-D Legendre series at points (x, y).
920
921
This function returns the values:
922
923
.. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y)
924
925
The parameters `x` and `y` are converted to arrays only if they are
926
tuples or a lists, otherwise they are treated as a scalars and they
927
must have the same shape after conversion. In either case, either `x`
928
and `y` or their elements must support multiplication and addition both
929
with themselves and with the elements of `c`.
930
931
If `c` is a 1-D array a one is implicitly appended to its shape to make
932
it 2-D. The shape of the result will be c.shape[2:] + x.shape.
933
934
Parameters
935
----------
936
x, y : array_like, compatible objects
937
The two dimensional series is evaluated at the points `(x, y)`,
938
where `x` and `y` must have the same shape. If `x` or `y` is a list
939
or tuple, it is first converted to an ndarray, otherwise it is left
940
unchanged and if it isn't an ndarray it is treated as a scalar.
941
c : array_like
942
Array of coefficients ordered so that the coefficient of the term
943
of multi-degree i,j is contained in ``c[i,j]``. If `c` has
944
dimension greater than two the remaining indices enumerate multiple
945
sets of coefficients.
946
947
Returns
948
-------
949
values : ndarray, compatible object
950
The values of the two dimensional Legendre series at points formed
951
from pairs of corresponding values from `x` and `y`.
952
953
See Also
954
--------
955
legval, leggrid2d, legval3d, leggrid3d
956
957
Notes
958
-----
959
960
.. versionadded:: 1.7.0
961
962
"""
963
return pu._valnd(legval, c, x, y)
964
965
966
def leggrid2d(x, y, c):
967
"""
968
Evaluate a 2-D Legendre series on the Cartesian product of x and y.
969
970
This function returns the values:
971
972
.. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b)
973
974
where the points `(a, b)` consist of all pairs formed by taking
975
`a` from `x` and `b` from `y`. The resulting points form a grid with
976
`x` in the first dimension and `y` in the second.
977
978
The parameters `x` and `y` are converted to arrays only if they are
979
tuples or a lists, otherwise they are treated as a scalars. In either
980
case, either `x` and `y` or their elements must support multiplication
981
and addition both with themselves and with the elements of `c`.
982
983
If `c` has fewer than two dimensions, ones are implicitly appended to
984
its shape to make it 2-D. The shape of the result will be c.shape[2:] +
985
x.shape + y.shape.
986
987
Parameters
988
----------
989
x, y : array_like, compatible objects
990
The two dimensional series is evaluated at the points in the
991
Cartesian product of `x` and `y`. If `x` or `y` is a list or
992
tuple, it is first converted to an ndarray, otherwise it is left
993
unchanged and, if it isn't an ndarray, it is treated as a scalar.
994
c : array_like
995
Array of coefficients ordered so that the coefficient of the term of
996
multi-degree i,j is contained in `c[i,j]`. If `c` has dimension
997
greater than two the remaining indices enumerate multiple sets of
998
coefficients.
999
1000
Returns
1001
-------
1002
values : ndarray, compatible object
1003
The values of the two dimensional Chebyshev series at points in the
1004
Cartesian product of `x` and `y`.
1005
1006
See Also
1007
--------
1008
legval, legval2d, legval3d, leggrid3d
1009
1010
Notes
1011
-----
1012
1013
.. versionadded:: 1.7.0
1014
1015
"""
1016
return pu._gridnd(legval, c, x, y)
1017
1018
1019
def legval3d(x, y, z, c):
1020
"""
1021
Evaluate a 3-D Legendre series at points (x, y, z).
1022
1023
This function returns the values:
1024
1025
.. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z)
1026
1027
The parameters `x`, `y`, and `z` are converted to arrays only if
1028
they are tuples or a lists, otherwise they are treated as a scalars and
1029
they must have the same shape after conversion. In either case, either
1030
`x`, `y`, and `z` or their elements must support multiplication and
1031
addition both with themselves and with the elements of `c`.
1032
1033
If `c` has fewer than 3 dimensions, ones are implicitly appended to its
1034
shape to make it 3-D. The shape of the result will be c.shape[3:] +
1035
x.shape.
1036
1037
Parameters
1038
----------
1039
x, y, z : array_like, compatible object
1040
The three dimensional series is evaluated at the points
1041
`(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If
1042
any of `x`, `y`, or `z` is a list or tuple, it is first converted
1043
to an ndarray, otherwise it is left unchanged and if it isn't an
1044
ndarray it is treated as a scalar.
1045
c : array_like
1046
Array of coefficients ordered so that the coefficient of the term of
1047
multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension
1048
greater than 3 the remaining indices enumerate multiple sets of
1049
coefficients.
1050
1051
Returns
1052
-------
1053
values : ndarray, compatible object
1054
The values of the multidimensional polynomial on points formed with
1055
triples of corresponding values from `x`, `y`, and `z`.
1056
1057
See Also
1058
--------
1059
legval, legval2d, leggrid2d, leggrid3d
1060
1061
Notes
1062
-----
1063
1064
.. versionadded:: 1.7.0
1065
1066
"""
1067
return pu._valnd(legval, c, x, y, z)
1068
1069
1070
def leggrid3d(x, y, z, c):
1071
"""
1072
Evaluate a 3-D Legendre series on the Cartesian product of x, y, and z.
1073
1074
This function returns the values:
1075
1076
.. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c)
1077
1078
where the points `(a, b, c)` consist of all triples formed by taking
1079
`a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form
1080
a grid with `x` in the first dimension, `y` in the second, and `z` in
1081
the third.
1082
1083
The parameters `x`, `y`, and `z` are converted to arrays only if they
1084
are tuples or a lists, otherwise they are treated as a scalars. In
1085
either case, either `x`, `y`, and `z` or their elements must support
1086
multiplication and addition both with themselves and with the elements
1087
of `c`.
1088
1089
If `c` has fewer than three dimensions, ones are implicitly appended to
1090
its shape to make it 3-D. The shape of the result will be c.shape[3:] +
1091
x.shape + y.shape + z.shape.
1092
1093
Parameters
1094
----------
1095
x, y, z : array_like, compatible objects
1096
The three dimensional series is evaluated at the points in the
1097
Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a
1098
list or tuple, it is first converted to an ndarray, otherwise it is
1099
left unchanged and, if it isn't an ndarray, it is treated as a
1100
scalar.
1101
c : array_like
1102
Array of coefficients ordered so that the coefficients for terms of
1103
degree i,j are contained in ``c[i,j]``. If `c` has dimension
1104
greater than two the remaining indices enumerate multiple sets of
1105
coefficients.
1106
1107
Returns
1108
-------
1109
values : ndarray, compatible object
1110
The values of the two dimensional polynomial at points in the Cartesian
1111
product of `x` and `y`.
1112
1113
See Also
1114
--------
1115
legval, legval2d, leggrid2d, legval3d
1116
1117
Notes
1118
-----
1119
1120
.. versionadded:: 1.7.0
1121
1122
"""
1123
return pu._gridnd(legval, c, x, y, z)
1124
1125
1126
def legvander(x, deg):
1127
"""Pseudo-Vandermonde matrix of given degree.
1128
1129
Returns the pseudo-Vandermonde matrix of degree `deg` and sample points
1130
`x`. The pseudo-Vandermonde matrix is defined by
1131
1132
.. math:: V[..., i] = L_i(x)
1133
1134
where `0 <= i <= deg`. The leading indices of `V` index the elements of
1135
`x` and the last index is the degree of the Legendre polynomial.
1136
1137
If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the
1138
array ``V = legvander(x, n)``, then ``np.dot(V, c)`` and
1139
``legval(x, c)`` are the same up to roundoff. This equivalence is
1140
useful both for least squares fitting and for the evaluation of a large
1141
number of Legendre series of the same degree and sample points.
1142
1143
Parameters
1144
----------
1145
x : array_like
1146
Array of points. The dtype is converted to float64 or complex128
1147
depending on whether any of the elements are complex. If `x` is
1148
scalar it is converted to a 1-D array.
1149
deg : int
1150
Degree of the resulting matrix.
1151
1152
Returns
1153
-------
1154
vander : ndarray
1155
The pseudo-Vandermonde matrix. The shape of the returned matrix is
1156
``x.shape + (deg + 1,)``, where The last index is the degree of the
1157
corresponding Legendre polynomial. The dtype will be the same as
1158
the converted `x`.
1159
1160
"""
1161
ideg = pu._deprecate_as_int(deg, "deg")
1162
if ideg < 0:
1163
raise ValueError("deg must be non-negative")
1164
1165
x = np.array(x, copy=False, ndmin=1) + 0.0
1166
dims = (ideg + 1,) + x.shape
1167
dtyp = x.dtype
1168
v = np.empty(dims, dtype=dtyp)
1169
# Use forward recursion to generate the entries. This is not as accurate
1170
# as reverse recursion in this application but it is more efficient.
1171
v[0] = x*0 + 1
1172
if ideg > 0:
1173
v[1] = x
1174
for i in range(2, ideg + 1):
1175
v[i] = (v[i-1]*x*(2*i - 1) - v[i-2]*(i - 1))/i
1176
return np.moveaxis(v, 0, -1)
1177
1178
1179
def legvander2d(x, y, deg):
1180
"""Pseudo-Vandermonde matrix of given degrees.
1181
1182
Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
1183
points `(x, y)`. The pseudo-Vandermonde matrix is defined by
1184
1185
.. math:: V[..., (deg[1] + 1)*i + j] = L_i(x) * L_j(y),
1186
1187
where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of
1188
`V` index the points `(x, y)` and the last index encodes the degrees of
1189
the Legendre polynomials.
1190
1191
If ``V = legvander2d(x, y, [xdeg, ydeg])``, then the columns of `V`
1192
correspond to the elements of a 2-D coefficient array `c` of shape
1193
(xdeg + 1, ydeg + 1) in the order
1194
1195
.. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ...
1196
1197
and ``np.dot(V, c.flat)`` and ``legval2d(x, y, c)`` will be the same
1198
up to roundoff. This equivalence is useful both for least squares
1199
fitting and for the evaluation of a large number of 2-D Legendre
1200
series of the same degrees and sample points.
1201
1202
Parameters
1203
----------
1204
x, y : array_like
1205
Arrays of point coordinates, all of the same shape. The dtypes
1206
will be converted to either float64 or complex128 depending on
1207
whether any of the elements are complex. Scalars are converted to
1208
1-D arrays.
1209
deg : list of ints
1210
List of maximum degrees of the form [x_deg, y_deg].
1211
1212
Returns
1213
-------
1214
vander2d : ndarray
1215
The shape of the returned matrix is ``x.shape + (order,)``, where
1216
:math:`order = (deg[0]+1)*(deg[1]+1)`. The dtype will be the same
1217
as the converted `x` and `y`.
1218
1219
See Also
1220
--------
1221
legvander, legvander3d, legval2d, legval3d
1222
1223
Notes
1224
-----
1225
1226
.. versionadded:: 1.7.0
1227
1228
"""
1229
return pu._vander_nd_flat((legvander, legvander), (x, y), deg)
1230
1231
1232
def legvander3d(x, y, z, deg):
1233
"""Pseudo-Vandermonde matrix of given degrees.
1234
1235
Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
1236
points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`,
1237
then The pseudo-Vandermonde matrix is defined by
1238
1239
.. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = L_i(x)*L_j(y)*L_k(z),
1240
1241
where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading
1242
indices of `V` index the points `(x, y, z)` and the last index encodes
1243
the degrees of the Legendre polynomials.
1244
1245
If ``V = legvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns
1246
of `V` correspond to the elements of a 3-D coefficient array `c` of
1247
shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order
1248
1249
.. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...
1250
1251
and ``np.dot(V, c.flat)`` and ``legval3d(x, y, z, c)`` will be the
1252
same up to roundoff. This equivalence is useful both for least squares
1253
fitting and for the evaluation of a large number of 3-D Legendre
1254
series of the same degrees and sample points.
1255
1256
Parameters
1257
----------
1258
x, y, z : array_like
1259
Arrays of point coordinates, all of the same shape. The dtypes will
1260
be converted to either float64 or complex128 depending on whether
1261
any of the elements are complex. Scalars are converted to 1-D
1262
arrays.
1263
deg : list of ints
1264
List of maximum degrees of the form [x_deg, y_deg, z_deg].
1265
1266
Returns
1267
-------
1268
vander3d : ndarray
1269
The shape of the returned matrix is ``x.shape + (order,)``, where
1270
:math:`order = (deg[0]+1)*(deg[1]+1)*(deg[2]+1)`. The dtype will
1271
be the same as the converted `x`, `y`, and `z`.
1272
1273
See Also
1274
--------
1275
legvander, legvander3d, legval2d, legval3d
1276
1277
Notes
1278
-----
1279
1280
.. versionadded:: 1.7.0
1281
1282
"""
1283
return pu._vander_nd_flat((legvander, legvander, legvander), (x, y, z), deg)
1284
1285
1286
def legfit(x, y, deg, rcond=None, full=False, w=None):
1287
"""
1288
Least squares fit of Legendre series to data.
1289
1290
Return the coefficients of a Legendre series of degree `deg` that is the
1291
least squares fit to the data values `y` given at points `x`. If `y` is
1292
1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple
1293
fits are done, one for each column of `y`, and the resulting
1294
coefficients are stored in the corresponding columns of a 2-D return.
1295
The fitted polynomial(s) are in the form
1296
1297
.. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x),
1298
1299
where `n` is `deg`.
1300
1301
Parameters
1302
----------
1303
x : array_like, shape (M,)
1304
x-coordinates of the M sample points ``(x[i], y[i])``.
1305
y : array_like, shape (M,) or (M, K)
1306
y-coordinates of the sample points. Several data sets of sample
1307
points sharing the same x-coordinates can be fitted at once by
1308
passing in a 2D-array that contains one dataset per column.
1309
deg : int or 1-D array_like
1310
Degree(s) of the fitting polynomials. If `deg` is a single integer
1311
all terms up to and including the `deg`'th term are included in the
1312
fit. For NumPy versions >= 1.11.0 a list of integers specifying the
1313
degrees of the terms to include may be used instead.
1314
rcond : float, optional
1315
Relative condition number of the fit. Singular values smaller than
1316
this relative to the largest singular value will be ignored. The
1317
default value is len(x)*eps, where eps is the relative precision of
1318
the float type, about 2e-16 in most cases.
1319
full : bool, optional
1320
Switch determining nature of return value. When it is False (the
1321
default) just the coefficients are returned, when True diagnostic
1322
information from the singular value decomposition is also returned.
1323
w : array_like, shape (`M`,), optional
1324
Weights. If not None, the weight ``w[i]`` applies to the unsquared
1325
residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are
1326
chosen so that the errors of the products ``w[i]*y[i]`` all have the
1327
same variance. When using inverse-variance weighting, use
1328
``w[i] = 1/sigma(y[i])``. The default value is None.
1329
1330
.. versionadded:: 1.5.0
1331
1332
Returns
1333
-------
1334
coef : ndarray, shape (M,) or (M, K)
1335
Legendre coefficients ordered from low to high. If `y` was
1336
2-D, the coefficients for the data in column k of `y` are in
1337
column `k`. If `deg` is specified as a list, coefficients for
1338
terms not included in the fit are set equal to zero in the
1339
returned `coef`.
1340
1341
[residuals, rank, singular_values, rcond] : list
1342
These values are only returned if ``full == True``
1343
1344
- residuals -- sum of squared residuals of the least squares fit
1345
- rank -- the numerical rank of the scaled Vandermonde matrix
1346
- singular_values -- singular values of the scaled Vandermonde matrix
1347
- rcond -- value of `rcond`.
1348
1349
For more details, see `numpy.linalg.lstsq`.
1350
1351
Warns
1352
-----
1353
RankWarning
1354
The rank of the coefficient matrix in the least-squares fit is
1355
deficient. The warning is only raised if ``full == False``. The
1356
warnings can be turned off by
1357
1358
>>> import warnings
1359
>>> warnings.simplefilter('ignore', np.RankWarning)
1360
1361
See Also
1362
--------
1363
numpy.polynomial.polynomial.polyfit
1364
numpy.polynomial.chebyshev.chebfit
1365
numpy.polynomial.laguerre.lagfit
1366
numpy.polynomial.hermite.hermfit
1367
numpy.polynomial.hermite_e.hermefit
1368
legval : Evaluates a Legendre series.
1369
legvander : Vandermonde matrix of Legendre series.
1370
legweight : Legendre weight function (= 1).
1371
numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
1372
scipy.interpolate.UnivariateSpline : Computes spline fits.
1373
1374
Notes
1375
-----
1376
The solution is the coefficients of the Legendre series `p` that
1377
minimizes the sum of the weighted squared errors
1378
1379
.. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,
1380
1381
where :math:`w_j` are the weights. This problem is solved by setting up
1382
as the (typically) overdetermined matrix equation
1383
1384
.. math:: V(x) * c = w * y,
1385
1386
where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the
1387
coefficients to be solved for, `w` are the weights, and `y` are the
1388
observed values. This equation is then solved using the singular value
1389
decomposition of `V`.
1390
1391
If some of the singular values of `V` are so small that they are
1392
neglected, then a `RankWarning` will be issued. This means that the
1393
coefficient values may be poorly determined. Using a lower order fit
1394
will usually get rid of the warning. The `rcond` parameter can also be
1395
set to a value smaller than its default, but the resulting fit may be
1396
spurious and have large contributions from roundoff error.
1397
1398
Fits using Legendre series are usually better conditioned than fits
1399
using power series, but much can depend on the distribution of the
1400
sample points and the smoothness of the data. If the quality of the fit
1401
is inadequate splines may be a good alternative.
1402
1403
References
1404
----------
1405
.. [1] Wikipedia, "Curve fitting",
1406
https://en.wikipedia.org/wiki/Curve_fitting
1407
1408
Examples
1409
--------
1410
1411
"""
1412
return pu._fit(legvander, x, y, deg, rcond, full, w)
1413
1414
1415
def legcompanion(c):
1416
"""Return the scaled companion matrix of c.
1417
1418
The basis polynomials are scaled so that the companion matrix is
1419
symmetric when `c` is an Legendre basis polynomial. This provides
1420
better eigenvalue estimates than the unscaled case and for basis
1421
polynomials the eigenvalues are guaranteed to be real if
1422
`numpy.linalg.eigvalsh` is used to obtain them.
1423
1424
Parameters
1425
----------
1426
c : array_like
1427
1-D array of Legendre series coefficients ordered from low to high
1428
degree.
1429
1430
Returns
1431
-------
1432
mat : ndarray
1433
Scaled companion matrix of dimensions (deg, deg).
1434
1435
Notes
1436
-----
1437
1438
.. versionadded:: 1.7.0
1439
1440
"""
1441
# c is a trimmed copy
1442
[c] = pu.as_series([c])
1443
if len(c) < 2:
1444
raise ValueError('Series must have maximum degree of at least 1.')
1445
if len(c) == 2:
1446
return np.array([[-c[0]/c[1]]])
1447
1448
n = len(c) - 1
1449
mat = np.zeros((n, n), dtype=c.dtype)
1450
scl = 1./np.sqrt(2*np.arange(n) + 1)
1451
top = mat.reshape(-1)[1::n+1]
1452
bot = mat.reshape(-1)[n::n+1]
1453
top[...] = np.arange(1, n)*scl[:n-1]*scl[1:n]
1454
bot[...] = top
1455
mat[:, -1] -= (c[:-1]/c[-1])*(scl/scl[-1])*(n/(2*n - 1))
1456
return mat
1457
1458
1459
def legroots(c):
1460
"""
1461
Compute the roots of a Legendre series.
1462
1463
Return the roots (a.k.a. "zeros") of the polynomial
1464
1465
.. math:: p(x) = \\sum_i c[i] * L_i(x).
1466
1467
Parameters
1468
----------
1469
c : 1-D array_like
1470
1-D array of coefficients.
1471
1472
Returns
1473
-------
1474
out : ndarray
1475
Array of the roots of the series. If all the roots are real,
1476
then `out` is also real, otherwise it is complex.
1477
1478
See Also
1479
--------
1480
numpy.polynomial.polynomial.polyroots
1481
numpy.polynomial.chebyshev.chebroots
1482
numpy.polynomial.laguerre.lagroots
1483
numpy.polynomial.hermite.hermroots
1484
numpy.polynomial.hermite_e.hermeroots
1485
1486
Notes
1487
-----
1488
The root estimates are obtained as the eigenvalues of the companion
1489
matrix, Roots far from the origin of the complex plane may have large
1490
errors due to the numerical instability of the series for such values.
1491
Roots with multiplicity greater than 1 will also show larger errors as
1492
the value of the series near such points is relatively insensitive to
1493
errors in the roots. Isolated roots near the origin can be improved by
1494
a few iterations of Newton's method.
1495
1496
The Legendre series basis polynomials aren't powers of ``x`` so the
1497
results of this function may seem unintuitive.
1498
1499
Examples
1500
--------
1501
>>> import numpy.polynomial.legendre as leg
1502
>>> leg.legroots((1, 2, 3, 4)) # 4L_3 + 3L_2 + 2L_1 + 1L_0, all real roots
1503
array([-0.85099543, -0.11407192, 0.51506735]) # may vary
1504
1505
"""
1506
# c is a trimmed copy
1507
[c] = pu.as_series([c])
1508
if len(c) < 2:
1509
return np.array([], dtype=c.dtype)
1510
if len(c) == 2:
1511
return np.array([-c[0]/c[1]])
1512
1513
# rotated companion matrix reduces error
1514
m = legcompanion(c)[::-1,::-1]
1515
r = la.eigvals(m)
1516
r.sort()
1517
return r
1518
1519
1520
def leggauss(deg):
1521
"""
1522
Gauss-Legendre quadrature.
1523
1524
Computes the sample points and weights for Gauss-Legendre quadrature.
1525
These sample points and weights will correctly integrate polynomials of
1526
degree :math:`2*deg - 1` or less over the interval :math:`[-1, 1]` with
1527
the weight function :math:`f(x) = 1`.
1528
1529
Parameters
1530
----------
1531
deg : int
1532
Number of sample points and weights. It must be >= 1.
1533
1534
Returns
1535
-------
1536
x : ndarray
1537
1-D ndarray containing the sample points.
1538
y : ndarray
1539
1-D ndarray containing the weights.
1540
1541
Notes
1542
-----
1543
1544
.. versionadded:: 1.7.0
1545
1546
The results have only been tested up to degree 100, higher degrees may
1547
be problematic. The weights are determined by using the fact that
1548
1549
.. math:: w_k = c / (L'_n(x_k) * L_{n-1}(x_k))
1550
1551
where :math:`c` is a constant independent of :math:`k` and :math:`x_k`
1552
is the k'th root of :math:`L_n`, and then scaling the results to get
1553
the right value when integrating 1.
1554
1555
"""
1556
ideg = pu._deprecate_as_int(deg, "deg")
1557
if ideg <= 0:
1558
raise ValueError("deg must be a positive integer")
1559
1560
# first approximation of roots. We use the fact that the companion
1561
# matrix is symmetric in this case in order to obtain better zeros.
1562
c = np.array([0]*deg + [1])
1563
m = legcompanion(c)
1564
x = la.eigvalsh(m)
1565
1566
# improve roots by one application of Newton
1567
dy = legval(x, c)
1568
df = legval(x, legder(c))
1569
x -= dy/df
1570
1571
# compute the weights. We scale the factor to avoid possible numerical
1572
# overflow.
1573
fm = legval(x, c[1:])
1574
fm /= np.abs(fm).max()
1575
df /= np.abs(df).max()
1576
w = 1/(fm * df)
1577
1578
# for Legendre we can also symmetrize
1579
w = (w + w[::-1])/2
1580
x = (x - x[::-1])/2
1581
1582
# scale w to get the right value
1583
w *= 2. / w.sum()
1584
1585
return x, w
1586
1587
1588
def legweight(x):
1589
"""
1590
Weight function of the Legendre polynomials.
1591
1592
The weight function is :math:`1` and the interval of integration is
1593
:math:`[-1, 1]`. The Legendre polynomials are orthogonal, but not
1594
normalized, with respect to this weight function.
1595
1596
Parameters
1597
----------
1598
x : array_like
1599
Values at which the weight function will be computed.
1600
1601
Returns
1602
-------
1603
w : ndarray
1604
The weight function at `x`.
1605
1606
Notes
1607
-----
1608
1609
.. versionadded:: 1.7.0
1610
1611
"""
1612
w = x*0.0 + 1.0
1613
return w
1614
1615
#
1616
# Legendre series class
1617
#
1618
1619
class Legendre(ABCPolyBase):
1620
"""A Legendre series class.
1621
1622
The Legendre class provides the standard Python numerical methods
1623
'+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the
1624
attributes and methods listed in the `ABCPolyBase` documentation.
1625
1626
Parameters
1627
----------
1628
coef : array_like
1629
Legendre coefficients in order of increasing degree, i.e.,
1630
``(1, 2, 3)`` gives ``1*P_0(x) + 2*P_1(x) + 3*P_2(x)``.
1631
domain : (2,) array_like, optional
1632
Domain to use. The interval ``[domain[0], domain[1]]`` is mapped
1633
to the interval ``[window[0], window[1]]`` by shifting and scaling.
1634
The default value is [-1, 1].
1635
window : (2,) array_like, optional
1636
Window, see `domain` for its use. The default value is [-1, 1].
1637
1638
.. versionadded:: 1.6.0
1639
1640
"""
1641
# Virtual Functions
1642
_add = staticmethod(legadd)
1643
_sub = staticmethod(legsub)
1644
_mul = staticmethod(legmul)
1645
_div = staticmethod(legdiv)
1646
_pow = staticmethod(legpow)
1647
_val = staticmethod(legval)
1648
_int = staticmethod(legint)
1649
_der = staticmethod(legder)
1650
_fit = staticmethod(legfit)
1651
_line = staticmethod(legline)
1652
_roots = staticmethod(legroots)
1653
_fromroots = staticmethod(legfromroots)
1654
1655
# Virtual properties
1656
domain = np.array(legdomain)
1657
window = np.array(legdomain)
1658
basis_name = 'P'
1659
1660