Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/numpy/polynomial/legendre.py: 16%

261 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

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 

83import numpy.linalg as la 

84from numpy.core.multiarray import normalize_axis_index 

85 

86from . import polyutils as pu 

87from ._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 

97legtrim = pu.trimcoef 

98 

99 

100def 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 

148def 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.legendre.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 

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 `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, 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 .. 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 

704def 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 

832def 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 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 

917def 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 

966def 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 

1019def 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 

1070def 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 

1126def 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 

1179def 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 

1232def 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 

1286def 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 

1415def 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 

1459def 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 

1520def 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 

1588def 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 

1619class 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'