1"""

2==================================================

3 Laguerre Series (:mod:`numpy.polynomial.laguerre`)

4==================================================

5

6 This module provides a number of objects (mostly functions) useful for

7 dealing with Laguerre series, including a `Laguerre` 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 Laguerre

18

19 Constants

20---------

21.. autosummary::

22 :toctree: generated/

23

24 lagdomain

25 lagzero

26 lagone

27 lagx

28

29 Arithmetic

30----------

31.. autosummary::

32 :toctree: generated/

33

34 lagadd

35 lagsub

36 lagmulx

37 lagmul

38 lagdiv

39 lagpow

40 lagval

41 lagval2d

42 lagval3d

43 laggrid2d

44 laggrid3d

45

46 Calculus

47--------

48.. autosummary::

49 :toctree: generated/

50

51 lagder

52 lagint

53

54 Misc Functions

55--------------

56.. autosummary::

57 :toctree: generated/

58

59 lagfromroots

60 lagroots

61 lagvander

62 lagvander2d

63 lagvander3d

64 laggauss

65 lagweight

66 lagcompanion

67 lagfit

68 lagtrim

69 lagline

70 lag2poly

71 poly2lag

72

73 See also

74--------

75`numpy.polynomial`

76

77"""

78 import numpy as np

79 import numpy.linalg as la

80 from numpy.core.multiarray import normalize_axis_index

81

82 from . import polyutils as pu

83 from ._polybase import ABCPolyBase

84

85__all__ = [

86 'lagzero', 'lagone', 'lagx', 'lagdomain', 'lagline', 'lagadd',

87 'lagsub', 'lagmulx', 'lagmul', 'lagdiv', 'lagpow', 'lagval', 'lagder',

88 'lagint', 'lag2poly', 'poly2lag', 'lagfromroots', 'lagvander',

89 'lagfit', 'lagtrim', 'lagroots', 'Laguerre', 'lagval2d', 'lagval3d',

90 'laggrid2d', 'laggrid3d', 'lagvander2d', 'lagvander3d', 'lagcompanion',

91 'laggauss', 'lagweight']

92

93 lagtrim = pu.trimcoef

94

95

96 def poly2lag(pol):

97 """

98 poly2lag(pol)

99

100 Convert a polynomial to a Laguerre series.

101

102 Convert an array representing the coefficients of a polynomial (relative

103 to the "standard" basis) ordered from lowest degree to highest, to an

104 array of the coefficients of the equivalent Laguerre series, ordered

105 from lowest to highest degree.

106

107 Parameters

108 ----------

109 pol : array_like

110 1-D array containing the polynomial coefficients

111

112 Returns

113 -------

114 c : ndarray

115 1-D array containing the coefficients of the equivalent Laguerre

116 series.

117

118 See Also

119 --------

120 lag2poly

121

122 Notes

123 -----

124 The easy way to do conversions between polynomial basis sets

125 is to use the convert method of a class instance.

126

127 Examples

128 --------

129 >>> from numpy.polynomial.laguerre import poly2lag

130 >>> poly2lag(np.arange(4))

131 array([ 23., -63., 58., -18.])

132

133 """

134 [pol] = pu.as_series([pol])

135 res = 0

136 for p in pol[::-1]:

137 res = lagadd(lagmulx(res), p)

138 return res

139

140

141 def lag2poly(c):

142 """

143 Convert a Laguerre series to a polynomial.

144

145 Convert an array representing the coefficients of a Laguerre series,

146 ordered from lowest degree to highest, to an array of the coefficients

147 of the equivalent polynomial (relative to the "standard" basis) ordered

148 from lowest to highest degree.

149

150 Parameters

151 ----------

152 c : array_like

153 1-D array containing the Laguerre series coefficients, ordered

154 from lowest order term to highest.

155

156 Returns

157 -------

158 pol : ndarray

159 1-D array containing the coefficients of the equivalent polynomial

160 (relative to the "standard" basis) ordered from lowest order term

161 to highest.

162

163 See Also

164 --------

165 poly2lag

166

167 Notes

168 -----

169 The easy way to do conversions between polynomial basis sets

170 is to use the convert method of a class instance.

171

172 Examples

173 --------

174 >>> from numpy.polynomial.laguerre import lag2poly

175 >>> lag2poly([ 23., -63., 58., -18.])

176 array([0., 1., 2., 3.])

177

178 """

179 from .polynomial import polyadd, polysub, polymulx

180

181 [c] = pu.as_series([c])

182 n = len(c)

183 if n == 1:

184 return c

185 else:

186 c0 = c[-2]

187 c1 = c[-1]

188 # i is the current degree of c1

189 for i in range(n - 1, 1, -1):

190 tmp = c0

191 c0 = polysub(c[i - 2], (c1*(i - 1))/i)

192 c1 = polyadd(tmp, polysub((2*i - 1)*c1, polymulx(c1))/i)

193 return polyadd(c0, polysub(c1, polymulx(c1)))

194

195#

196# These are constant arrays are of integer type so as to be compatible

197# with the widest range of other types, such as Decimal.

198#

199

200# Laguerre

201 lagdomain = np.array([0, 1])

202

203# Laguerre coefficients representing zero.

204 lagzero = np.array([0])

205

206# Laguerre coefficients representing one.

207 lagone = np.array([1])

208

209# Laguerre coefficients representing the identity x.

210 lagx = np.array([1, -1])

211

212

213 def lagline(off, scl):

214 """

215 Laguerre series whose graph is a straight line.

216

217 Parameters

218 ----------

219 off, scl : scalars

220 The specified line is given by ``off + scl*x``.

221

222 Returns

223 -------

224 y : ndarray

225 This module's representation of the Laguerre series for

226 ``off + scl*x``.

227

228 See Also

229 --------

230 numpy.polynomial.polynomial.polyline

231 numpy.polynomial.chebyshev.chebline

232 numpy.polynomial.legendre.legline

233 numpy.polynomial.hermite.hermline

234 numpy.polynomial.hermite_e.hermeline

235

236 Examples

237 --------

238 >>> from numpy.polynomial.laguerre import lagline, lagval

239 >>> lagval(0,lagline(3, 2))

240 3.0

241 >>> lagval(1,lagline(3, 2))

242 5.0

243

244 """

245 if scl != 0:

246 return np.array([off + scl, -scl])

247 else:

248 return np.array([off])

249

250

251 def lagfromroots(roots):

252 """

253 Generate a Laguerre series with given roots.

254

255 The function returns the coefficients of the polynomial

256

257 .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n),

258

259 in Laguerre form, where the `r_n` are the roots specified in `roots`.

260 If a zero has multiplicity n, then it must appear in `roots` n times.

261 For instance, if 2 is a root of multiplicity three and 3 is a root of

262 multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The

263 roots can appear in any order.

264

265 If the returned coefficients are `c`, then

266

267 .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x)

268

269 The coefficient of the last term is not generally 1 for monic

270 polynomials in Laguerre form.

271

272 Parameters

273 ----------

274 roots : array_like

275 Sequence containing the roots.

276

277 Returns

278 -------

279 out : ndarray

280 1-D array of coefficients. If all roots are real then `out` is a

281 real array, if some of the roots are complex, then `out` is complex

282 even if all the coefficients in the result are real (see Examples

283 below).

284

285 See Also

286 --------

287 numpy.polynomial.polynomial.polyfromroots

288 numpy.polynomial.legendre.legfromroots

289 numpy.polynomial.chebyshev.chebfromroots

290 numpy.polynomial.hermite.hermfromroots

291 numpy.polynomial.hermite_e.hermefromroots

292

293 Examples

294 --------

295 >>> from numpy.polynomial.laguerre import lagfromroots, lagval

296 >>> coef = lagfromroots((-1, 0, 1))

297 >>> lagval((-1, 0, 1), coef)

298 array([0., 0., 0.])

299 >>> coef = lagfromroots((-1j, 1j))

300 >>> lagval((-1j, 1j), coef)

301 array([0.+0.j, 0.+0.j])

302

303 """

304 return pu._fromroots(lagline, lagmul, roots)

305

306

307 def lagadd(c1, c2):

308 """

309 Add one Laguerre series to another.

310

311 Returns the sum of two Laguerre series `c1` + `c2`. The arguments

312 are sequences of coefficients ordered from lowest order term to

313 highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.

314

315 Parameters

316 ----------

317 c1, c2 : array_like

318 1-D arrays of Laguerre series coefficients ordered from low to

319 high.

320

321 Returns

322 -------

323 out : ndarray

324 Array representing the Laguerre series of their sum.

325

326 See Also

327 --------

328 lagsub, lagmulx, lagmul, lagdiv, lagpow

329

330 Notes

331 -----

332 Unlike multiplication, division, etc., the sum of two Laguerre series

333 is a Laguerre series (without having to "reproject" the result onto

334 the basis set) so addition, just like that of "standard" polynomials,

335 is simply "component-wise."

336

337 Examples

338 --------

339 >>> from numpy.polynomial.laguerre import lagadd

340 >>> lagadd([1, 2, 3], [1, 2, 3, 4])

341 array([2., 4., 6., 4.])

342

343

344 """

345 return pu._add(c1, c2)

346

347

348 def lagsub(c1, c2):

349 """

350 Subtract one Laguerre series from another.

351

352 Returns the difference of two Laguerre series `c1` - `c2`. The

353 sequences of coefficients are from lowest order term to highest, i.e.,

354 [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.

355

356 Parameters

357 ----------

358 c1, c2 : array_like

359 1-D arrays of Laguerre series coefficients ordered from low to

360 high.

361

362 Returns

363 -------

364 out : ndarray

365 Of Laguerre series coefficients representing their difference.

366

367 See Also

368 --------

369 lagadd, lagmulx, lagmul, lagdiv, lagpow

370

371 Notes

372 -----

373 Unlike multiplication, division, etc., the difference of two Laguerre

374 series is a Laguerre series (without having to "reproject" the result

375 onto the basis set) so subtraction, just like that of "standard"

376 polynomials, is simply "component-wise."

377

378 Examples

379 --------

380 >>> from numpy.polynomial.laguerre import lagsub

381 >>> lagsub([1, 2, 3, 4], [1, 2, 3])

382 array([0., 0., 0., 4.])

383

384 """

385 return pu._sub(c1, c2)

386

387

388 def lagmulx(c):

389 """Multiply a Laguerre series by x.

390

391 Multiply the Laguerre series `c` by x, where x is the independent

392 variable.

393

394

395 Parameters

396 ----------

397 c : array_like

398 1-D array of Laguerre series coefficients ordered from low to

399 high.

400

401 Returns

402 -------

403 out : ndarray

404 Array representing the result of the multiplication.

405

406 See Also

407 --------

408 lagadd, lagsub, lagmul, lagdiv, lagpow

409

410 Notes

411 -----

412 The multiplication uses the recursion relationship for Laguerre

413 polynomials in the form

414

415 .. math::

416

417 xP_i(x) = (-(i + 1)*P_{i + 1}(x) + (2i + 1)P_{i}(x) - iP_{i - 1}(x))

418

419 Examples

420 --------

421 >>> from numpy.polynomial.laguerre import lagmulx

422 >>> lagmulx([1, 2, 3])

423 array([-1., -1., 11., -9.])

424

425 """

426 # c is a trimmed copy

427 [c] = pu.as_series([c])

428 # The zero series needs special treatment

429 if len(c) == 1 and c[0] == 0:

430 return c

431

432 prd = np.empty(len(c) + 1, dtype=c.dtype)

433 prd[0] = c[0]

434 prd[1] = -c[0]

435 for i in range(1, len(c)):

436 prd[i + 1] = -c[i]*(i + 1)

437 prd[i] += c[i]*(2*i + 1)

438 prd[i - 1] -= c[i]*i

439 return prd

440

441

442 def lagmul(c1, c2):

443 """

444 Multiply one Laguerre series by another.

445

446 Returns the product of two Laguerre series `c1` * `c2`. The arguments

447 are sequences of coefficients, from lowest order "term" to highest,

448 e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.

449

450 Parameters

451 ----------

452 c1, c2 : array_like

453 1-D arrays of Laguerre series coefficients ordered from low to

454 high.

455

456 Returns

457 -------

458 out : ndarray

459 Of Laguerre series coefficients representing their product.

460

461 See Also

462 --------

463 lagadd, lagsub, lagmulx, lagdiv, lagpow

464

465 Notes

466 -----

467 In general, the (polynomial) product of two C-series results in terms

468 that are not in the Laguerre polynomial basis set. Thus, to express

469 the product as a Laguerre series, it is necessary to "reproject" the

470 product onto said basis set, which may produce "unintuitive" (but

471 correct) results; see Examples section below.

472

473 Examples

474 --------

475 >>> from numpy.polynomial.laguerre import lagmul

476 >>> lagmul([1, 2, 3], [0, 1, 2])

477 array([ 8., -13., 38., -51., 36.])

478

479 """

480 # s1, s2 are trimmed copies

481 [c1, c2] = pu.as_series([c1, c2])

482

483 if len(c1) > len(c2):

484 c = c2

485 xs = c1

486 else:

487 c = c1

488 xs = c2

489

490 if len(c) == 1:

491 c0 = c[0]*xs

492 c1 = 0

493 elif len(c) == 2:

494 c0 = c[0]*xs

495 c1 = c[1]*xs

496 else:

497 nd = len(c)

498 c0 = c[-2]*xs

499 c1 = c[-1]*xs

500 for i in range(3, len(c) + 1):

501 tmp = c0

502 nd = nd - 1

503 c0 = lagsub(c[-i]*xs, (c1*(nd - 1))/nd)

504 c1 = lagadd(tmp, lagsub((2*nd - 1)*c1, lagmulx(c1))/nd)

505 return lagadd(c0, lagsub(c1, lagmulx(c1)))

506

507

508 def lagdiv(c1, c2):

509 """

510 Divide one Laguerre series by another.

511

512 Returns the quotient-with-remainder of two Laguerre series

513 `c1` / `c2`. The arguments are sequences of coefficients from lowest

514 order "term" to highest, e.g., [1,2,3] represents the series

515 ``P_0 + 2*P_1 + 3*P_2``.

516

517 Parameters

518 ----------

519 c1, c2 : array_like

520 1-D arrays of Laguerre series coefficients ordered from low to

521 high.

522

523 Returns

524 -------

525 [quo, rem] : ndarrays

526 Of Laguerre series coefficients representing the quotient and

527 remainder.

528

529 See Also

530 --------

531 lagadd, lagsub, lagmulx, lagmul, lagpow

532

533 Notes

534 -----

535 In general, the (polynomial) division of one Laguerre series by another

536 results in quotient and remainder terms that are not in the Laguerre

537 polynomial basis set. Thus, to express these results as a Laguerre

538 series, it is necessary to "reproject" the results onto the Laguerre

539 basis set, which may produce "unintuitive" (but correct) results; see

540 Examples section below.

541

542 Examples

543 --------

544 >>> from numpy.polynomial.laguerre import lagdiv

545 >>> lagdiv([ 8., -13., 38., -51., 36.], [0, 1, 2])

546 (array([1., 2., 3.]), array([0.]))

547 >>> lagdiv([ 9., -12., 38., -51., 36.], [0, 1, 2])

548 (array([1., 2., 3.]), array([1., 1.]))

549

550 """

551 return pu._div(lagmul, c1, c2)

552

553

554 def lagpow(c, pow, maxpower=16):

555 """Raise a Laguerre series to a power.

556

557 Returns the Laguerre series `c` raised to the power `pow`. The

558 argument `c` is a sequence of coefficients ordered from low to high.

559 i.e., [1,2,3] is the series ``P_0 + 2*P_1 + 3*P_2.``

560

561 Parameters

562 ----------

563 c : array_like

564 1-D array of Laguerre series coefficients ordered from low to

565 high.

566 pow : integer

567 Power to which the series will be raised

568 maxpower : integer, optional

569 Maximum power allowed. This is mainly to limit growth of the series

570 to unmanageable size. Default is 16

571

572 Returns

573 -------

574 coef : ndarray

575 Laguerre series of power.

576

577 See Also

578 --------

579 lagadd, lagsub, lagmulx, lagmul, lagdiv

580

581 Examples

582 --------

583 >>> from numpy.polynomial.laguerre import lagpow

584 >>> lagpow([1, 2, 3], 2)

585 array([ 14., -16., 56., -72., 54.])

586

587 """

588 return pu._pow(lagmul, c, pow, maxpower)

589

590

591 def lagder(c, m=1, scl=1, axis=0):

592 """

593 Differentiate a Laguerre series.

594

595 Returns the Laguerre series coefficients `c` differentiated `m` times

596 along `axis`. At each iteration the result is multiplied by `scl` (the

597 scaling factor is for use in a linear change of variable). The argument

598 `c` is an array of coefficients from low to high degree along each

599 axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2``

600 while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) +

601 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is

602 ``y``.

603

604 Parameters

605 ----------

606 c : array_like

607 Array of Laguerre series coefficients. If `c` is multidimensional

608 the different axis correspond to different variables with the

609 degree in each axis given by the corresponding index.

610 m : int, optional

611 Number of derivatives taken, must be non-negative. (Default: 1)

612 scl : scalar, optional

613 Each differentiation is multiplied by `scl`. The end result is

614 multiplication by ``scl**m``. This is for use in a linear change of

615 variable. (Default: 1)

616 axis : int, optional

617 Axis over which the derivative is taken. (Default: 0).

618

619 .. versionadded:: 1.7.0

620

621 Returns

622 -------

623 der : ndarray

624 Laguerre series of the derivative.

625

626 See Also

627 --------

628 lagint

629

630 Notes

631 -----

632 In general, the result of differentiating a Laguerre series does not

633 resemble the same operation on a power series. Thus the result of this

634 function may be "unintuitive," albeit correct; see Examples section

635 below.

636

637 Examples

638 --------

639 >>> from numpy.polynomial.laguerre import lagder

640 >>> lagder([ 1., 1., 1., -3.])

641 array([1., 2., 3.])

642 >>> lagder([ 1., 0., 0., -4., 3.], m=2)

643 array([1., 2., 3.])

644

645 """

646 c = np.array(c, ndmin=1, copy=True)

647 if c.dtype.char in '?bBhHiIlLqQpP':

648 c = c.astype(np.double)

649

650 cnt = pu._deprecate_as_int(m, "the order of derivation")

651 iaxis = pu._deprecate_as_int(axis, "the axis")

652 if cnt < 0:

653 raise ValueError("The order of derivation must be non-negative")

654 iaxis = normalize_axis_index(iaxis, c.ndim)

655

656 if cnt == 0:

657 return c

658

659 c = np.moveaxis(c, iaxis, 0)

660 n = len(c)

661 if cnt >= n:

662 c = c[:1]*0

663 else:

664 for i in range(cnt):

665 n = n - 1

666 c *= scl

667 der = np.empty((n,) + c.shape[1:], dtype=c.dtype)

668 for j in range(n, 1, -1):

669 der[j - 1] = -c[j]

670 c[j - 1] += c[j]

671 der[0] = -c[1]

672 c = der

673 c = np.moveaxis(c, 0, iaxis)

674 return c

675

676

677 def lagint(c, m=1, k=[], lbnd=0, scl=1, axis=0):

678 """

679 Integrate a Laguerre series.

680

681 Returns the Laguerre series coefficients `c` integrated `m` times from

682 `lbnd` along `axis`. At each iteration the resulting series is

683 **multiplied** by `scl` and an integration constant, `k`, is added.

684 The scaling factor is for use in a linear change of variable. ("Buyer

685 beware": note that, depending on what one is doing, one may want `scl`

686 to be the reciprocal of what one might expect; for more information,

687 see the Notes section below.) The argument `c` is an array of

688 coefficients from low to high degree along each axis, e.g., [1,2,3]

689 represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]]

690 represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) +

691 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.

692

693

694 Parameters

695 ----------

696 c : array_like

697 Array of Laguerre series coefficients. If `c` is multidimensional

698 the different axis correspond to different variables with the

699 degree in each axis given by the corresponding index.

700 m : int, optional

701 Order of integration, must be positive. (Default: 1)

702 k : {[], list, scalar}, optional

703 Integration constant(s). The value of the first integral at

704 ``lbnd`` is the first value in the list, the value of the second

705 integral at ``lbnd`` is the second value, etc. If ``k == []`` (the

706 default), all constants are set to zero. If ``m == 1``, a single

707 scalar can be given instead of a list.

708 lbnd : scalar, optional

709 The lower bound of the integral. (Default: 0)

710 scl : scalar, optional

711 Following each integration the result is *multiplied* by `scl`

712 before the integration constant is added. (Default: 1)

713 axis : int, optional

714 Axis over which the integral is taken. (Default: 0).

715

716 .. versionadded:: 1.7.0

717

718 Returns

719 -------

720 S : ndarray

721 Laguerre series coefficients of the integral.

722

723 Raises

724 ------

725 ValueError

726 If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or

727 ``np.ndim(scl) != 0``.

728

729 See Also

730 --------

731 lagder

732

733 Notes

734 -----

735 Note that the result of each integration is *multiplied* by `scl`.

736 Why is this important to note? Say one is making a linear change of

737 variable :math:`u = ax + b` in an integral relative to `x`. Then

738 :math:`dx = du/a`, so one will need to set `scl` equal to

739 :math:`1/a` - perhaps not what one would have first thought.

740

741 Also note that, in general, the result of integrating a C-series needs

742 to be "reprojected" onto the C-series basis set. Thus, typically,

743 the result of this function is "unintuitive," albeit correct; see

744 Examples section below.

745

746 Examples

747 --------

748 >>> from numpy.polynomial.laguerre import lagint

749 >>> lagint([1,2,3])

750 array([ 1., 1., 1., -3.])

751 >>> lagint([1,2,3], m=2)

752 array([ 1., 0., 0., -4., 3.])

753 >>> lagint([1,2,3], k=1)

754 array([ 2., 1., 1., -3.])

755 >>> lagint([1,2,3], lbnd=-1)

756 array([11.5, 1. , 1. , -3. ])

757 >>> lagint([1,2], m=2, k=[1,2], lbnd=-1)

758 array([ 11.16666667, -5. , -3. , 2. ]) # may vary

759

760 """

761 c = np.array(c, ndmin=1, copy=True)

762 if c.dtype.char in '?bBhHiIlLqQpP':

763 c = c.astype(np.double)

764 if not np.iterable(k):

765 k = [k]

766 cnt = pu._deprecate_as_int(m, "the order of integration")

767 iaxis = pu._deprecate_as_int(axis, "the axis")

768 if cnt < 0:

769 raise ValueError("The order of integration must be non-negative")

770 if len(k) > cnt:

771 raise ValueError("Too many integration constants")

772 if np.ndim(lbnd) != 0:

773 raise ValueError("lbnd must be a scalar.")

774 if np.ndim(scl) != 0:

775 raise ValueError("scl must be a scalar.")

776 iaxis = normalize_axis_index(iaxis, c.ndim)

777

778 if cnt == 0:

779 return c

780

781 c = np.moveaxis(c, iaxis, 0)

782 k = list(k) + [0]*(cnt - len(k))

783 for i in range(cnt):

784 n = len(c)

785 c *= scl

786 if n == 1 and np.all(c[0] == 0):

787 c[0] += k[i]

788 else:

789 tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)

790 tmp[0] = c[0]

791 tmp[1] = -c[0]

792 for j in range(1, n):

793 tmp[j] += c[j]

794 tmp[j + 1] = -c[j]

795 tmp[0] += k[i] - lagval(lbnd, tmp)

796 c = tmp

797 c = np.moveaxis(c, 0, iaxis)

798 return c

799

800

801 def lagval(x, c, tensor=True):

802 """

803 Evaluate a Laguerre series at points x.

804

805 If `c` is of length `n + 1`, this function returns the value:

806

807 .. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x)

808

809 The parameter `x` is converted to an array only if it is a tuple or a

810 list, otherwise it is treated as a scalar. In either case, either `x`

811 or its elements must support multiplication and addition both with

812 themselves and with the elements of `c`.

813

814 If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If

815 `c` is multidimensional, then the shape of the result depends on the

816 value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +

817 x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that

818 scalars have shape (,).

819

820 Trailing zeros in the coefficients will be used in the evaluation, so

821 they should be avoided if efficiency is a concern.

822

823 Parameters

824 ----------

825 x : array_like, compatible object

826 If `x` is a list or tuple, it is converted to an ndarray, otherwise

827 it is left unchanged and treated as a scalar. In either case, `x`

828 or its elements must support addition and multiplication with

829 themselves and with the elements of `c`.

830 c : array_like

831 Array of coefficients ordered so that the coefficients for terms of

832 degree n are contained in c[n]. If `c` is multidimensional the

833 remaining indices enumerate multiple polynomials. In the two

834 dimensional case the coefficients may be thought of as stored in

835 the columns of `c`.

836 tensor : boolean, optional

837 If True, the shape of the coefficient array is extended with ones

838 on the right, one for each dimension of `x`. Scalars have dimension 0

839 for this action. The result is that every column of coefficients in

840 `c` is evaluated for every element of `x`. If False, `x` is broadcast

841 over the columns of `c` for the evaluation. This keyword is useful

842 when `c` is multidimensional. The default value is True.

843

844 .. versionadded:: 1.7.0

845

846 Returns

847 -------

848 values : ndarray, algebra_like

849 The shape of the return value is described above.

850

851 See Also

852 --------

853 lagval2d, laggrid2d, lagval3d, laggrid3d

854

855 Notes

856 -----

857 The evaluation uses Clenshaw recursion, aka synthetic division.

858

859 Examples

860 --------

861 >>> from numpy.polynomial.laguerre import lagval

862 >>> coef = [1,2,3]

863 >>> lagval(1, coef)

864 -0.5

865 >>> lagval([[1,2],[3,4]], coef)

866 array([[-0.5, -4. ],

867 [-4.5, -2. ]])

868

869 """

870 c = np.array(c, ndmin=1, copy=False)

871 if c.dtype.char in '?bBhHiIlLqQpP':

872 c = c.astype(np.double)

873 if isinstance(x, (tuple, list)):

874 x = np.asarray(x)

875 if isinstance(x, np.ndarray) and tensor:

876 c = c.reshape(c.shape + (1,)*x.ndim)

877

878 if len(c) == 1:

879 c0 = c[0]

880 c1 = 0

881 elif len(c) == 2:

882 c0 = c[0]

883 c1 = c[1]

884 else:

885 nd = len(c)

886 c0 = c[-2]

887 c1 = c[-1]

888 for i in range(3, len(c) + 1):

889 tmp = c0

890 nd = nd - 1

891 c0 = c[-i] - (c1*(nd - 1))/nd

892 c1 = tmp + (c1*((2*nd - 1) - x))/nd

893 return c0 + c1*(1 - x)

894

895

896 def lagval2d(x, y, c):

897 """

898 Evaluate a 2-D Laguerre series at points (x, y).

899

900 This function returns the values:

901

902 .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y)

903

904 The parameters `x` and `y` are converted to arrays only if they are

905 tuples or a lists, otherwise they are treated as a scalars and they

906 must have the same shape after conversion. In either case, either `x`

907 and `y` or their elements must support multiplication and addition both

908 with themselves and with the elements of `c`.

909

910 If `c` is a 1-D array a one is implicitly appended to its shape to make

911 it 2-D. The shape of the result will be c.shape[2:] + x.shape.

912

913 Parameters

914 ----------

915 x, y : array_like, compatible objects

916 The two dimensional series is evaluated at the points `(x, y)`,

917 where `x` and `y` must have the same shape. If `x` or `y` is a list

918 or tuple, it is first converted to an ndarray, otherwise it is left

919 unchanged and if it isn't an ndarray it is treated as a scalar.

920 c : array_like

921 Array of coefficients ordered so that the coefficient of the term

922 of multi-degree i,j is contained in ``c[i,j]``. If `c` has

923 dimension greater than two the remaining indices enumerate multiple

924 sets of coefficients.

925

926 Returns

927 -------

928 values : ndarray, compatible object

929 The values of the two dimensional polynomial at points formed with

930 pairs of corresponding values from `x` and `y`.

931

932 See Also

933 --------

934 lagval, laggrid2d, lagval3d, laggrid3d

935

936 Notes

937 -----

938

939 .. versionadded:: 1.7.0

940

941 """

942 return pu._valnd(lagval, c, x, y)

943

944

945 def laggrid2d(x, y, c):

946 """

947 Evaluate a 2-D Laguerre series on the Cartesian product of x and y.

948

949 This function returns the values:

950

951 .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b)

952

953 where the points `(a, b)` consist of all pairs formed by taking

954 `a` from `x` and `b` from `y`. The resulting points form a grid with

955 `x` in the first dimension and `y` in the second.

956

957 The parameters `x` and `y` are converted to arrays only if they are

958 tuples or a lists, otherwise they are treated as a scalars. In either

959 case, either `x` and `y` or their elements must support multiplication

960 and addition both with themselves and with the elements of `c`.

961

962 If `c` has fewer than two dimensions, ones are implicitly appended to

963 its shape to make it 2-D. The shape of the result will be c.shape[2:] +

964 x.shape + y.shape.

965

966 Parameters

967 ----------

968 x, y : array_like, compatible objects

969 The two dimensional series is evaluated at the points in the

970 Cartesian product of `x` and `y`. If `x` or `y` is a list or

971 tuple, it is first converted to an ndarray, otherwise it is left

972 unchanged and, if it isn't an ndarray, it is treated as a scalar.

973 c : array_like

974 Array of coefficients ordered so that the coefficient of the term of

975 multi-degree i,j is contained in `c[i,j]`. If `c` has dimension

976 greater than two the remaining indices enumerate multiple sets of

977 coefficients.

978

979 Returns

980 -------

981 values : ndarray, compatible object

982 The values of the two dimensional Chebyshev series at points in the

983 Cartesian product of `x` and `y`.

984

985 See Also

986 --------

987 lagval, lagval2d, lagval3d, laggrid3d

988

989 Notes

990 -----

991

992 .. versionadded:: 1.7.0

993

994 """

995 return pu._gridnd(lagval, c, x, y)

996

997

998 def lagval3d(x, y, z, c):

999 """

1000 Evaluate a 3-D Laguerre series at points (x, y, z).

1001

1002 This function returns the values:

1003

1004 .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z)

1005

1006 The parameters `x`, `y`, and `z` are converted to arrays only if

1007 they are tuples or a lists, otherwise they are treated as a scalars and

1008 they must have the same shape after conversion. In either case, either

1009 `x`, `y`, and `z` or their elements must support multiplication and

1010 addition both with themselves and with the elements of `c`.

1011

1012 If `c` has fewer than 3 dimensions, ones are implicitly appended to its

1013 shape to make it 3-D. The shape of the result will be c.shape[3:] +

1014 x.shape.

1015

1016 Parameters

1017 ----------

1018 x, y, z : array_like, compatible object

1019 The three dimensional series is evaluated at the points

1020 `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If

1021 any of `x`, `y`, or `z` is a list or tuple, it is first converted

1022 to an ndarray, otherwise it is left unchanged and if it isn't an

1023 ndarray it is treated as a scalar.

1024 c : array_like

1025 Array of coefficients ordered so that the coefficient of the term of

1026 multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension

1027 greater than 3 the remaining indices enumerate multiple sets of

1028 coefficients.

1029

1030 Returns

1031 -------

1032 values : ndarray, compatible object

1033 The values of the multidimensional polynomial on points formed with

1034 triples of corresponding values from `x`, `y`, and `z`.

1035

1036 See Also

1037 --------

1038 lagval, lagval2d, laggrid2d, laggrid3d

1039

1040 Notes

1041 -----

1042

1043 .. versionadded:: 1.7.0

1044

1045 """

1046 return pu._valnd(lagval, c, x, y, z)

1047

1048

1049 def laggrid3d(x, y, z, c):

1050 """

1051 Evaluate a 3-D Laguerre series on the Cartesian product of x, y, and z.

1052

1053 This function returns the values:

1054

1055 .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c)

1056

1057 where the points `(a, b, c)` consist of all triples formed by taking

1058 `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form

1059 a grid with `x` in the first dimension, `y` in the second, and `z` in

1060 the third.

1061

1062 The parameters `x`, `y`, and `z` are converted to arrays only if they

1063 are tuples or a lists, otherwise they are treated as a scalars. In

1064 either case, either `x`, `y`, and `z` or their elements must support

1065 multiplication and addition both with themselves and with the elements

1066 of `c`.

1067

1068 If `c` has fewer than three dimensions, ones are implicitly appended to

1069 its shape to make it 3-D. The shape of the result will be c.shape[3:] +

1070 x.shape + y.shape + z.shape.

1071

1072 Parameters

1073 ----------

1074 x, y, z : array_like, compatible objects

1075 The three dimensional series is evaluated at the points in the

1076 Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a

1077 list or tuple, it is first converted to an ndarray, otherwise it is

1078 left unchanged and, if it isn't an ndarray, it is treated as a

1079 scalar.

1080 c : array_like

1081 Array of coefficients ordered so that the coefficients for terms of

1082 degree i,j are contained in ``c[i,j]``. If `c` has dimension

1083 greater than two the remaining indices enumerate multiple sets of

1084 coefficients.

1085

1086 Returns

1087 -------

1088 values : ndarray, compatible object

1089 The values of the two dimensional polynomial at points in the Cartesian

1090 product of `x` and `y`.

1091

1092 See Also

1093 --------

1094 lagval, lagval2d, laggrid2d, lagval3d

1095

1096 Notes

1097 -----

1098

1099 .. versionadded:: 1.7.0

1100

1101 """

1102 return pu._gridnd(lagval, c, x, y, z)

1103

1104

1105 def lagvander(x, deg):

1106 """Pseudo-Vandermonde matrix of given degree.

1107

1108 Returns the pseudo-Vandermonde matrix of degree `deg` and sample points

1109 `x`. The pseudo-Vandermonde matrix is defined by

1110

1111 .. math:: V[..., i] = L_i(x)

1112

1113 where `0 <= i <= deg`. The leading indices of `V` index the elements of

1114 `x` and the last index is the degree of the Laguerre polynomial.

1115

1116 If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the

1117 array ``V = lagvander(x, n)``, then ``np.dot(V, c)`` and

1118 ``lagval(x, c)`` are the same up to roundoff. This equivalence is

1119 useful both for least squares fitting and for the evaluation of a large

1120 number of Laguerre series of the same degree and sample points.

1121

1122 Parameters

1123 ----------

1124 x : array_like

1125 Array of points. The dtype is converted to float64 or complex128

1126 depending on whether any of the elements are complex. If `x` is

1127 scalar it is converted to a 1-D array.

1128 deg : int

1129 Degree of the resulting matrix.

1130

1131 Returns

1132 -------

1133 vander : ndarray

1134 The pseudo-Vandermonde matrix. The shape of the returned matrix is

1135 ``x.shape + (deg + 1,)``, where The last index is the degree of the

1136 corresponding Laguerre polynomial. The dtype will be the same as

1137 the converted `x`.

1138

1139 Examples

1140 --------

1141 >>> from numpy.polynomial.laguerre import lagvander

1142 >>> x = np.array([0, 1, 2])

1143 >>> lagvander(x, 3)

1144 array([[ 1. , 1. , 1. , 1. ],

1145 [ 1. , 0. , -0.5 , -0.66666667],

1146 [ 1. , -1. , -1. , -0.33333333]])

1147

1148 """

1149 ideg = pu._deprecate_as_int(deg, "deg")

1150 if ideg < 0:

1151 raise ValueError("deg must be non-negative")

1152

1153 x = np.array(x, copy=False, ndmin=1) + 0.0

1154 dims = (ideg + 1,) + x.shape

1155 dtyp = x.dtype

1156 v = np.empty(dims, dtype=dtyp)

1157 v[0] = x*0 + 1

1158 if ideg > 0:

1159 v[1] = 1 - x

1160 for i in range(2, ideg + 1):

1161 v[i] = (v[i-1]*(2*i - 1 - x) - v[i-2]*(i - 1))/i

1162 return np.moveaxis(v, 0, -1)

1163

1164

1165 def lagvander2d(x, y, deg):

1166 """Pseudo-Vandermonde matrix of given degrees.

1167

1168 Returns the pseudo-Vandermonde matrix of degrees `deg` and sample

1169 points `(x, y)`. The pseudo-Vandermonde matrix is defined by

1170

1171 .. math:: V[..., (deg[1] + 1)*i + j] = L_i(x) * L_j(y),

1172

1173 where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of

1174 `V` index the points `(x, y)` and the last index encodes the degrees of

1175 the Laguerre polynomials.

1176

1177 If ``V = lagvander2d(x, y, [xdeg, ydeg])``, then the columns of `V`

1178 correspond to the elements of a 2-D coefficient array `c` of shape

1179 (xdeg + 1, ydeg + 1) in the order

1180

1181 .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ...

1182

1183 and ``np.dot(V, c.flat)`` and ``lagval2d(x, y, c)`` will be the same

1184 up to roundoff. This equivalence is useful both for least squares

1185 fitting and for the evaluation of a large number of 2-D Laguerre

1186 series of the same degrees and sample points.

1187

1188 Parameters

1189 ----------

1190 x, y : array_like

1191 Arrays of point coordinates, all of the same shape. The dtypes

1192 will be converted to either float64 or complex128 depending on

1193 whether any of the elements are complex. Scalars are converted to

1194 1-D arrays.

1195 deg : list of ints

1196 List of maximum degrees of the form [x_deg, y_deg].

1197

1198 Returns

1199 -------

1200 vander2d : ndarray

1201 The shape of the returned matrix is ``x.shape + (order,)``, where

1202 :math:`order = (deg[0]+1)*(deg[1]+1)`. The dtype will be the same

1203 as the converted `x` and `y`.

1204

1205 See Also

1206 --------

1207 lagvander, lagvander3d, lagval2d, lagval3d

1208

1209 Notes

1210 -----

1211

1212 .. versionadded:: 1.7.0

1213

1214 """

1215 return pu._vander_nd_flat((lagvander, lagvander), (x, y), deg)

1216

1217

1218 def lagvander3d(x, y, z, deg):

1219 """Pseudo-Vandermonde matrix of given degrees.

1220

1221 Returns the pseudo-Vandermonde matrix of degrees `deg` and sample

1222 points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`,

1223 then The pseudo-Vandermonde matrix is defined by

1224

1225 .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = L_i(x)*L_j(y)*L_k(z),

1226

1227 where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading

1228 indices of `V` index the points `(x, y, z)` and the last index encodes

1229 the degrees of the Laguerre polynomials.

1230

1231 If ``V = lagvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns

1232 of `V` correspond to the elements of a 3-D coefficient array `c` of

1233 shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order

1234

1235 .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...

1236

1237 and ``np.dot(V, c.flat)`` and ``lagval3d(x, y, z, c)`` will be the

1238 same up to roundoff. This equivalence is useful both for least squares

1239 fitting and for the evaluation of a large number of 3-D Laguerre

1240 series of the same degrees and sample points.

1241

1242 Parameters

1243 ----------

1244 x, y, z : array_like

1245 Arrays of point coordinates, all of the same shape. The dtypes will

1246 be converted to either float64 or complex128 depending on whether

1247 any of the elements are complex. Scalars are converted to 1-D

1248 arrays.

1249 deg : list of ints

1250 List of maximum degrees of the form [x_deg, y_deg, z_deg].

1251

1252 Returns

1253 -------

1254 vander3d : ndarray

1255 The shape of the returned matrix is ``x.shape + (order,)``, where

1256 :math:`order = (deg[0]+1)*(deg[1]+1)*(deg[2]+1)`. The dtype will

1257 be the same as the converted `x`, `y`, and `z`.

1258

1259 See Also

1260 --------

1261 lagvander, lagvander3d, lagval2d, lagval3d

1262

1263 Notes

1264 -----

1265

1266 .. versionadded:: 1.7.0

1267

1268 """

1269 return pu._vander_nd_flat((lagvander, lagvander, lagvander), (x, y, z), deg)

1270

1271

1272 def lagfit(x, y, deg, rcond=None, full=False, w=None):

1273 """

1274 Least squares fit of Laguerre series to data.

1275

1276 Return the coefficients of a Laguerre series of degree `deg` that is the

1277 least squares fit to the data values `y` given at points `x`. If `y` is

1278 1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple

1279 fits are done, one for each column of `y`, and the resulting

1280 coefficients are stored in the corresponding columns of a 2-D return.

1281 The fitted polynomial(s) are in the form

1282

1283 .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x),

1284

1285 where ``n`` is `deg`.

1286

1287 Parameters

1288 ----------

1289 x : array_like, shape (M,)

1290 x-coordinates of the M sample points ``(x[i], y[i])``.

1291 y : array_like, shape (M,) or (M, K)

1292 y-coordinates of the sample points. Several data sets of sample

1293 points sharing the same x-coordinates can be fitted at once by

1294 passing in a 2D-array that contains one dataset per column.

1295 deg : int or 1-D array_like

1296 Degree(s) of the fitting polynomials. If `deg` is a single integer

1297 all terms up to and including the `deg`'th term are included in the

1298 fit. For NumPy versions >= 1.11.0 a list of integers specifying the

1299 degrees of the terms to include may be used instead.

1300 rcond : float, optional

1301 Relative condition number of the fit. Singular values smaller than

1302 this relative to the largest singular value will be ignored. The

1303 default value is len(x)*eps, where eps is the relative precision of

1304 the float type, about 2e-16 in most cases.

1305 full : bool, optional

1306 Switch determining nature of return value. When it is False (the

1307 default) just the coefficients are returned, when True diagnostic

1308 information from the singular value decomposition is also returned.

1309 w : array_like, shape (`M`,), optional

1310 Weights. If not None, the weight ``w[i]`` applies to the unsquared

1311 residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are

1312 chosen so that the errors of the products ``w[i]*y[i]`` all have the

1313 same variance. When using inverse-variance weighting, use

1314 ``w[i] = 1/sigma(y[i])``. The default value is None.

1315

1316 Returns

1317 -------

1318 coef : ndarray, shape (M,) or (M, K)

1319 Laguerre coefficients ordered from low to high. If `y` was 2-D,

1320 the coefficients for the data in column *k* of `y` are in column

1321 *k*.

1322

1323 [residuals, rank, singular_values, rcond] : list

1324 These values are only returned if ``full == True``

1325

1326 - residuals -- sum of squared residuals of the least squares fit

1327 - rank -- the numerical rank of the scaled Vandermonde matrix

1328 - singular_values -- singular values of the scaled Vandermonde matrix

1329 - rcond -- value of `rcond`.

1330

1331 For more details, see `numpy.linalg.lstsq`.

1332

1333 Warns

1334 -----

1335 RankWarning

1336 The rank of the coefficient matrix in the least-squares fit is

1337 deficient. The warning is only raised if ``full == False``. The

1338 warnings can be turned off by

1339

1340 >>> import warnings

1341 >>> warnings.simplefilter('ignore', np.RankWarning)

1342

1343 See Also

1344 --------

1345 numpy.polynomial.polynomial.polyfit

1346 numpy.polynomial.legendre.legfit

1347 numpy.polynomial.chebyshev.chebfit

1348 numpy.polynomial.hermite.hermfit

1349 numpy.polynomial.hermite_e.hermefit

1350 lagval : Evaluates a Laguerre series.

1351 lagvander : pseudo Vandermonde matrix of Laguerre series.

1352 lagweight : Laguerre weight function.

1353 numpy.linalg.lstsq : Computes a least-squares fit from the matrix.

1354 scipy.interpolate.UnivariateSpline : Computes spline fits.

1355

1356 Notes

1357 -----

1358 The solution is the coefficients of the Laguerre series ``p`` that

1359 minimizes the sum of the weighted squared errors

1360

1361 .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,

1362

1363 where the :math:`w_j` are the weights. This problem is solved by

1364 setting up as the (typically) overdetermined matrix equation

1365

1366 .. math:: V(x) * c = w * y,

1367

1368 where ``V`` is the weighted pseudo Vandermonde matrix of `x`, ``c`` are the

1369 coefficients to be solved for, `w` are the weights, and `y` are the

1370 observed values. This equation is then solved using the singular value

1371 decomposition of ``V``.

1372

1373 If some of the singular values of `V` are so small that they are

1374 neglected, then a `RankWarning` will be issued. This means that the

1375 coefficient values may be poorly determined. Using a lower order fit

1376 will usually get rid of the warning. The `rcond` parameter can also be

1377 set to a value smaller than its default, but the resulting fit may be

1378 spurious and have large contributions from roundoff error.

1379

1380 Fits using Laguerre series are probably most useful when the data can

1381 be approximated by ``sqrt(w(x)) * p(x)``, where ``w(x)`` is the Laguerre

1382 weight. In that case the weight ``sqrt(w(x[i]))`` should be used

1383 together with data values ``y[i]/sqrt(w(x[i]))``. The weight function is

1384 available as `lagweight`.

1385

1386 References

1387 ----------

1388 .. [1] Wikipedia, "Curve fitting",

1389 https://en.wikipedia.org/wiki/Curve_fitting

1390

1391 Examples

1392 --------

1393 >>> from numpy.polynomial.laguerre import lagfit, lagval

1394 >>> x = np.linspace(0, 10)

1395 >>> err = np.random.randn(len(x))/10

1396 >>> y = lagval(x, [1, 2, 3]) + err

1397 >>> lagfit(x, y, 2)

1398 array([ 0.96971004, 2.00193749, 3.00288744]) # may vary

1399

1400 """

1401 return pu._fit(lagvander, x, y, deg, rcond, full, w)

1402

1403

1404 def lagcompanion(c):

1405 """

1406 Return the companion matrix of c.

1407

1408 The usual companion matrix of the Laguerre polynomials is already

1409 symmetric when `c` is a basis Laguerre polynomial, so no scaling is

1410 applied.

1411

1412 Parameters

1413 ----------

1414 c : array_like

1415 1-D array of Laguerre series coefficients ordered from low to high

1416 degree.

1417

1418 Returns

1419 -------

1420 mat : ndarray

1421 Companion matrix of dimensions (deg, deg).

1422

1423 Notes

1424 -----

1425

1426 .. versionadded:: 1.7.0

1427

1428 """

1429 # c is a trimmed copy

1430 [c] = pu.as_series([c])

1431 if len(c) < 2:

1432 raise ValueError('Series must have maximum degree of at least 1.')

1433 if len(c) == 2:

1434 return np.array([[1 + c[0]/c[1]]])

1435

1436 n = len(c) - 1

1437 mat = np.zeros((n, n), dtype=c.dtype)

1438 top = mat.reshape(-1)[1::n+1]

1439 mid = mat.reshape(-1)[0::n+1]

1440 bot = mat.reshape(-1)[n::n+1]

1441 top[...] = -np.arange(1, n)

1442 mid[...] = 2.*np.arange(n) + 1.

1443 bot[...] = top

1444 mat[:, -1] += (c[:-1]/c[-1])*n

1445 return mat

1446

1447

1448 def lagroots(c):

1449 """

1450 Compute the roots of a Laguerre series.

1451

1452 Return the roots (a.k.a. "zeros") of the polynomial

1453

1454 .. math:: p(x) = \\sum_i c[i] * L_i(x).

1455

1456 Parameters

1457 ----------

1458 c : 1-D array_like

1459 1-D array of coefficients.

1460

1461 Returns

1462 -------

1463 out : ndarray

1464 Array of the roots of the series. If all the roots are real,

1465 then `out` is also real, otherwise it is complex.

1466

1467 See Also

1468 --------

1469 numpy.polynomial.polynomial.polyroots

1470 numpy.polynomial.legendre.legroots

1471 numpy.polynomial.chebyshev.chebroots

1472 numpy.polynomial.hermite.hermroots

1473 numpy.polynomial.hermite_e.hermeroots

1474

1475 Notes

1476 -----

1477 The root estimates are obtained as the eigenvalues of the companion

1478 matrix, Roots far from the origin of the complex plane may have large

1479 errors due to the numerical instability of the series for such

1480 values. Roots with multiplicity greater than 1 will also show larger

1481 errors as the value of the series near such points is relatively

1482 insensitive to errors in the roots. Isolated roots near the origin can

1483 be improved by a few iterations of Newton's method.

1484

1485 The Laguerre series basis polynomials aren't powers of `x` so the

1486 results of this function may seem unintuitive.

1487

1488 Examples

1489 --------

1490 >>> from numpy.polynomial.laguerre import lagroots, lagfromroots

1491 >>> coef = lagfromroots([0, 1, 2])

1492 >>> coef

1493 array([ 2., -8., 12., -6.])

1494 >>> lagroots(coef)

1495 array([-4.4408921e-16, 1.0000000e+00, 2.0000000e+00])

1496

1497 """

1498 # c is a trimmed copy

1499 [c] = pu.as_series([c])

1500 if len(c) <= 1:

1501 return np.array([], dtype=c.dtype)

1502 if len(c) == 2:

1503 return np.array([1 + c[0]/c[1]])

1504

1505 # rotated companion matrix reduces error

1506 m = lagcompanion(c)[::-1,::-1]

1507 r = la.eigvals(m)

1508 r.sort()

1509 return r

1510

1511

1512 def laggauss(deg):

1513 """

1514 Gauss-Laguerre quadrature.

1515

1516 Computes the sample points and weights for Gauss-Laguerre quadrature.

1517 These sample points and weights will correctly integrate polynomials of

1518 degree :math:`2*deg - 1` or less over the interval :math:`[0, \\inf]`

1519 with the weight function :math:`f(x) = \\exp(-x)`.

1520

1521 Parameters

1522 ----------

1523 deg : int

1524 Number of sample points and weights. It must be >= 1.

1525

1526 Returns

1527 -------

1528 x : ndarray

1529 1-D ndarray containing the sample points.

1530 y : ndarray

1531 1-D ndarray containing the weights.

1532

1533 Notes

1534 -----

1535

1536 .. versionadded:: 1.7.0

1537

1538 The results have only been tested up to degree 100 higher degrees may

1539 be problematic. The weights are determined by using the fact that

1540

1541 .. math:: w_k = c / (L'_n(x_k) * L_{n-1}(x_k))

1542

1543 where :math:`c` is a constant independent of :math:`k` and :math:`x_k`

1544 is the k'th root of :math:`L_n`, and then scaling the results to get

1545 the right value when integrating 1.

1546

1547 """

1548 ideg = pu._deprecate_as_int(deg, "deg")

1549 if ideg <= 0:

1550 raise ValueError("deg must be a positive integer")

1551

1552 # first approximation of roots. We use the fact that the companion

1553 # matrix is symmetric in this case in order to obtain better zeros.

1554 c = np.array([0]*deg + [1])

1555 m = lagcompanion(c)

1556 x = la.eigvalsh(m)

1557

1558 # improve roots by one application of Newton

1559 dy = lagval(x, c)

1560 df = lagval(x, lagder(c))

1561 x -= dy/df

1562

1563 # compute the weights. We scale the factor to avoid possible numerical

1564 # overflow.

1565 fm = lagval(x, c[1:])

1566 fm /= np.abs(fm).max()

1567 df /= np.abs(df).max()

1568 w = 1/(fm * df)

1569

1570 # scale w to get the right value, 1 in this case

1571 w /= w.sum()

1572

1573 return x, w

1574

1575

1576 def lagweight(x):

1577 """Weight function of the Laguerre polynomials.

1578

1579 The weight function is :math:`exp(-x)` and the interval of integration

1580 is :math:`[0, \\inf]`. The Laguerre polynomials are orthogonal, but not

1581 normalized, with respect to this weight function.

1582

1583 Parameters

1584 ----------

1585 x : array_like

1586 Values at which the weight function will be computed.

1587

1588 Returns

1589 -------

1590 w : ndarray

1591 The weight function at `x`.

1592

1593 Notes

1594 -----

1595

1596 .. versionadded:: 1.7.0

1597

1598 """

1599 w = np.exp(-x)

1600 return w

1601

1602#

1603# Laguerre series class

1604#

1605

1606 class Laguerre(ABCPolyBase):

1607 """A Laguerre series class.

1608

1609 The Laguerre class provides the standard Python numerical methods

1610 '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the

1611 attributes and methods listed in the `ABCPolyBase` documentation.

1612

1613 Parameters

1614 ----------

1615 coef : array_like

1616 Laguerre coefficients in order of increasing degree, i.e,

1617 ``(1, 2, 3)`` gives ``1*L_0(x) + 2*L_1(X) + 3*L_2(x)``.

1618 domain : (2,) array_like, optional

1619 Domain to use. The interval ``[domain[0], domain[1]]`` is mapped

1620 to the interval ``[window[0], window[1]]`` by shifting and scaling.

1621 The default value is [0, 1].

1622 window : (2,) array_like, optional

1623 Window, see `domain` for its use. The default value is [0, 1].

1624

1625 .. versionadded:: 1.6.0

1626

1627 """

1628 # Virtual Functions

1629 _add = staticmethod(lagadd)

1630 _sub = staticmethod(lagsub)

1631 _mul = staticmethod(lagmul)

1632 _div = staticmethod(lagdiv)

1633 _pow = staticmethod(lagpow)

1634 _val = staticmethod(lagval)

1635 _int = staticmethod(lagint)

1636 _der = staticmethod(lagder)

1637 _fit = staticmethod(lagfit)

1638 _line = staticmethod(lagline)

1639 _roots = staticmethod(lagroots)

1640 _fromroots = staticmethod(lagfromroots)

1641

1642 # Virtual properties

1643 domain = np.array(lagdomain)

1644 window = np.array(lagdomain)

1645 basis_name = 'L'