laguerre.py 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810
  1. """
  2. Objects for dealing with Laguerre series.
  3. This module provides a number of objects (mostly functions) useful for
  4. dealing with Laguerre series, including a `Laguerre` class that
  5. encapsulates the usual arithmetic operations. (General information
  6. on how this module represents and works with such polynomials is in the
  7. docstring for its "parent" sub-package, `numpy.polynomial`).
  8. Constants
  9. ---------
  10. - `lagdomain` -- Laguerre series default domain, [-1,1].
  11. - `lagzero` -- Laguerre series that evaluates identically to 0.
  12. - `lagone` -- Laguerre series that evaluates identically to 1.
  13. - `lagx` -- Laguerre series for the identity map, ``f(x) = x``.
  14. Arithmetic
  15. ----------
  16. - `lagadd` -- add two Laguerre series.
  17. - `lagsub` -- subtract one Laguerre series from another.
  18. - `lagmulx` -- multiply a Laguerre series in ``P_i(x)`` by ``x``.
  19. - `lagmul` -- multiply two Laguerre series.
  20. - `lagdiv` -- divide one Laguerre series by another.
  21. - `lagpow` -- raise a Laguerre series to a positive integer power.
  22. - `lagval` -- evaluate a Laguerre series at given points.
  23. - `lagval2d` -- evaluate a 2D Laguerre series at given points.
  24. - `lagval3d` -- evaluate a 3D Laguerre series at given points.
  25. - `laggrid2d` -- evaluate a 2D Laguerre series on a Cartesian product.
  26. - `laggrid3d` -- evaluate a 3D Laguerre series on a Cartesian product.
  27. Calculus
  28. --------
  29. - `lagder` -- differentiate a Laguerre series.
  30. - `lagint` -- integrate a Laguerre series.
  31. Misc Functions
  32. --------------
  33. - `lagfromroots` -- create a Laguerre series with specified roots.
  34. - `lagroots` -- find the roots of a Laguerre series.
  35. - `lagvander` -- Vandermonde-like matrix for Laguerre polynomials.
  36. - `lagvander2d` -- Vandermonde-like matrix for 2D power series.
  37. - `lagvander3d` -- Vandermonde-like matrix for 3D power series.
  38. - `laggauss` -- Gauss-Laguerre quadrature, points and weights.
  39. - `lagweight` -- Laguerre weight function.
  40. - `lagcompanion` -- symmetrized companion matrix in Laguerre form.
  41. - `lagfit` -- least-squares fit returning a Laguerre series.
  42. - `lagtrim` -- trim leading coefficients from a Laguerre series.
  43. - `lagline` -- Laguerre series of given straight line.
  44. - `lag2poly` -- convert a Laguerre series to a polynomial.
  45. - `poly2lag` -- convert a polynomial to a Laguerre series.
  46. Classes
  47. -------
  48. - `Laguerre` -- A Laguerre series class.
  49. See also
  50. --------
  51. `numpy.polynomial`
  52. """
  53. from __future__ import division, absolute_import, print_function
  54. import warnings
  55. import numpy as np
  56. import numpy.linalg as la
  57. from numpy.core.multiarray import normalize_axis_index
  58. from . import polyutils as pu
  59. from ._polybase import ABCPolyBase
  60. __all__ = [
  61. 'lagzero', 'lagone', 'lagx', 'lagdomain', 'lagline', 'lagadd',
  62. 'lagsub', 'lagmulx', 'lagmul', 'lagdiv', 'lagpow', 'lagval', 'lagder',
  63. 'lagint', 'lag2poly', 'poly2lag', 'lagfromroots', 'lagvander',
  64. 'lagfit', 'lagtrim', 'lagroots', 'Laguerre', 'lagval2d', 'lagval3d',
  65. 'laggrid2d', 'laggrid3d', 'lagvander2d', 'lagvander3d', 'lagcompanion',
  66. 'laggauss', 'lagweight']
  67. lagtrim = pu.trimcoef
  68. def poly2lag(pol):
  69. """
  70. poly2lag(pol)
  71. Convert a polynomial to a Laguerre series.
  72. Convert an array representing the coefficients of a polynomial (relative
  73. to the "standard" basis) ordered from lowest degree to highest, to an
  74. array of the coefficients of the equivalent Laguerre series, ordered
  75. from lowest to highest degree.
  76. Parameters
  77. ----------
  78. pol : array_like
  79. 1-D array containing the polynomial coefficients
  80. Returns
  81. -------
  82. c : ndarray
  83. 1-D array containing the coefficients of the equivalent Laguerre
  84. series.
  85. See Also
  86. --------
  87. lag2poly
  88. Notes
  89. -----
  90. The easy way to do conversions between polynomial basis sets
  91. is to use the convert method of a class instance.
  92. Examples
  93. --------
  94. >>> from numpy.polynomial.laguerre import poly2lag
  95. >>> poly2lag(np.arange(4))
  96. array([ 23., -63., 58., -18.])
  97. """
  98. [pol] = pu.as_series([pol])
  99. deg = len(pol) - 1
  100. res = 0
  101. for i in range(deg, -1, -1):
  102. res = lagadd(lagmulx(res), pol[i])
  103. return res
  104. def lag2poly(c):
  105. """
  106. Convert a Laguerre series to a polynomial.
  107. Convert an array representing the coefficients of a Laguerre series,
  108. ordered from lowest degree to highest, to an array of the coefficients
  109. of the equivalent polynomial (relative to the "standard" basis) ordered
  110. from lowest to highest degree.
  111. Parameters
  112. ----------
  113. c : array_like
  114. 1-D array containing the Laguerre series coefficients, ordered
  115. from lowest order term to highest.
  116. Returns
  117. -------
  118. pol : ndarray
  119. 1-D array containing the coefficients of the equivalent polynomial
  120. (relative to the "standard" basis) ordered from lowest order term
  121. to highest.
  122. See Also
  123. --------
  124. poly2lag
  125. Notes
  126. -----
  127. The easy way to do conversions between polynomial basis sets
  128. is to use the convert method of a class instance.
  129. Examples
  130. --------
  131. >>> from numpy.polynomial.laguerre import lag2poly
  132. >>> lag2poly([ 23., -63., 58., -18.])
  133. array([ 0., 1., 2., 3.])
  134. """
  135. from .polynomial import polyadd, polysub, polymulx
  136. [c] = pu.as_series([c])
  137. n = len(c)
  138. if n == 1:
  139. return c
  140. else:
  141. c0 = c[-2]
  142. c1 = c[-1]
  143. # i is the current degree of c1
  144. for i in range(n - 1, 1, -1):
  145. tmp = c0
  146. c0 = polysub(c[i - 2], (c1*(i - 1))/i)
  147. c1 = polyadd(tmp, polysub((2*i - 1)*c1, polymulx(c1))/i)
  148. return polyadd(c0, polysub(c1, polymulx(c1)))
  149. #
  150. # These are constant arrays are of integer type so as to be compatible
  151. # with the widest range of other types, such as Decimal.
  152. #
  153. # Laguerre
  154. lagdomain = np.array([0, 1])
  155. # Laguerre coefficients representing zero.
  156. lagzero = np.array([0])
  157. # Laguerre coefficients representing one.
  158. lagone = np.array([1])
  159. # Laguerre coefficients representing the identity x.
  160. lagx = np.array([1, -1])
  161. def lagline(off, scl):
  162. """
  163. Laguerre series whose graph is a straight line.
  164. Parameters
  165. ----------
  166. off, scl : scalars
  167. The specified line is given by ``off + scl*x``.
  168. Returns
  169. -------
  170. y : ndarray
  171. This module's representation of the Laguerre series for
  172. ``off + scl*x``.
  173. See Also
  174. --------
  175. polyline, chebline
  176. Examples
  177. --------
  178. >>> from numpy.polynomial.laguerre import lagline, lagval
  179. >>> lagval(0,lagline(3, 2))
  180. 3.0
  181. >>> lagval(1,lagline(3, 2))
  182. 5.0
  183. """
  184. if scl != 0:
  185. return np.array([off + scl, -scl])
  186. else:
  187. return np.array([off])
  188. def lagfromroots(roots):
  189. """
  190. Generate a Laguerre series with given roots.
  191. The function returns the coefficients of the polynomial
  192. .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n),
  193. in Laguerre form, where the `r_n` are the roots specified in `roots`.
  194. If a zero has multiplicity n, then it must appear in `roots` n times.
  195. For instance, if 2 is a root of multiplicity three and 3 is a root of
  196. multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The
  197. roots can appear in any order.
  198. If the returned coefficients are `c`, then
  199. .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x)
  200. The coefficient of the last term is not generally 1 for monic
  201. polynomials in Laguerre form.
  202. Parameters
  203. ----------
  204. roots : array_like
  205. Sequence containing the roots.
  206. Returns
  207. -------
  208. out : ndarray
  209. 1-D array of coefficients. If all roots are real then `out` is a
  210. real array, if some of the roots are complex, then `out` is complex
  211. even if all the coefficients in the result are real (see Examples
  212. below).
  213. See Also
  214. --------
  215. polyfromroots, legfromroots, chebfromroots, hermfromroots,
  216. hermefromroots.
  217. Examples
  218. --------
  219. >>> from numpy.polynomial.laguerre import lagfromroots, lagval
  220. >>> coef = lagfromroots((-1, 0, 1))
  221. >>> lagval((-1, 0, 1), coef)
  222. array([ 0., 0., 0.])
  223. >>> coef = lagfromroots((-1j, 1j))
  224. >>> lagval((-1j, 1j), coef)
  225. array([ 0.+0.j, 0.+0.j])
  226. """
  227. if len(roots) == 0:
  228. return np.ones(1)
  229. else:
  230. [roots] = pu.as_series([roots], trim=False)
  231. roots.sort()
  232. p = [lagline(-r, 1) for r in roots]
  233. n = len(p)
  234. while n > 1:
  235. m, r = divmod(n, 2)
  236. tmp = [lagmul(p[i], p[i+m]) for i in range(m)]
  237. if r:
  238. tmp[0] = lagmul(tmp[0], p[-1])
  239. p = tmp
  240. n = m
  241. return p[0]
  242. def lagadd(c1, c2):
  243. """
  244. Add one Laguerre series to another.
  245. Returns the sum of two Laguerre series `c1` + `c2`. The arguments
  246. are sequences of coefficients ordered from lowest order term to
  247. highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.
  248. Parameters
  249. ----------
  250. c1, c2 : array_like
  251. 1-D arrays of Laguerre series coefficients ordered from low to
  252. high.
  253. Returns
  254. -------
  255. out : ndarray
  256. Array representing the Laguerre series of their sum.
  257. See Also
  258. --------
  259. lagsub, lagmulx, lagmul, lagdiv, lagpow
  260. Notes
  261. -----
  262. Unlike multiplication, division, etc., the sum of two Laguerre series
  263. is a Laguerre series (without having to "reproject" the result onto
  264. the basis set) so addition, just like that of "standard" polynomials,
  265. is simply "component-wise."
  266. Examples
  267. --------
  268. >>> from numpy.polynomial.laguerre import lagadd
  269. >>> lagadd([1, 2, 3], [1, 2, 3, 4])
  270. array([ 2., 4., 6., 4.])
  271. """
  272. # c1, c2 are trimmed copies
  273. [c1, c2] = pu.as_series([c1, c2])
  274. if len(c1) > len(c2):
  275. c1[:c2.size] += c2
  276. ret = c1
  277. else:
  278. c2[:c1.size] += c1
  279. ret = c2
  280. return pu.trimseq(ret)
  281. def lagsub(c1, c2):
  282. """
  283. Subtract one Laguerre series from another.
  284. Returns the difference of two Laguerre series `c1` - `c2`. The
  285. sequences of coefficients are from lowest order term to highest, i.e.,
  286. [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.
  287. Parameters
  288. ----------
  289. c1, c2 : array_like
  290. 1-D arrays of Laguerre series coefficients ordered from low to
  291. high.
  292. Returns
  293. -------
  294. out : ndarray
  295. Of Laguerre series coefficients representing their difference.
  296. See Also
  297. --------
  298. lagadd, lagmulx, lagmul, lagdiv, lagpow
  299. Notes
  300. -----
  301. Unlike multiplication, division, etc., the difference of two Laguerre
  302. series is a Laguerre series (without having to "reproject" the result
  303. onto the basis set) so subtraction, just like that of "standard"
  304. polynomials, is simply "component-wise."
  305. Examples
  306. --------
  307. >>> from numpy.polynomial.laguerre import lagsub
  308. >>> lagsub([1, 2, 3, 4], [1, 2, 3])
  309. array([ 0., 0., 0., 4.])
  310. """
  311. # c1, c2 are trimmed copies
  312. [c1, c2] = pu.as_series([c1, c2])
  313. if len(c1) > len(c2):
  314. c1[:c2.size] -= c2
  315. ret = c1
  316. else:
  317. c2 = -c2
  318. c2[:c1.size] += c1
  319. ret = c2
  320. return pu.trimseq(ret)
  321. def lagmulx(c):
  322. """Multiply a Laguerre series by x.
  323. Multiply the Laguerre series `c` by x, where x is the independent
  324. variable.
  325. Parameters
  326. ----------
  327. c : array_like
  328. 1-D array of Laguerre series coefficients ordered from low to
  329. high.
  330. Returns
  331. -------
  332. out : ndarray
  333. Array representing the result of the multiplication.
  334. See Also
  335. --------
  336. lagadd, lagsub, lagmul, lagdiv, lagpow
  337. Notes
  338. -----
  339. The multiplication uses the recursion relationship for Laguerre
  340. polynomials in the form
  341. .. math::
  342. xP_i(x) = (-(i + 1)*P_{i + 1}(x) + (2i + 1)P_{i}(x) - iP_{i - 1}(x))
  343. Examples
  344. --------
  345. >>> from numpy.polynomial.laguerre import lagmulx
  346. >>> lagmulx([1, 2, 3])
  347. array([ -1., -1., 11., -9.])
  348. """
  349. # c is a trimmed copy
  350. [c] = pu.as_series([c])
  351. # The zero series needs special treatment
  352. if len(c) == 1 and c[0] == 0:
  353. return c
  354. prd = np.empty(len(c) + 1, dtype=c.dtype)
  355. prd[0] = c[0]
  356. prd[1] = -c[0]
  357. for i in range(1, len(c)):
  358. prd[i + 1] = -c[i]*(i + 1)
  359. prd[i] += c[i]*(2*i + 1)
  360. prd[i - 1] -= c[i]*i
  361. return prd
  362. def lagmul(c1, c2):
  363. """
  364. Multiply one Laguerre series by another.
  365. Returns the product of two Laguerre series `c1` * `c2`. The arguments
  366. are sequences of coefficients, from lowest order "term" to highest,
  367. e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``.
  368. Parameters
  369. ----------
  370. c1, c2 : array_like
  371. 1-D arrays of Laguerre series coefficients ordered from low to
  372. high.
  373. Returns
  374. -------
  375. out : ndarray
  376. Of Laguerre series coefficients representing their product.
  377. See Also
  378. --------
  379. lagadd, lagsub, lagmulx, lagdiv, lagpow
  380. Notes
  381. -----
  382. In general, the (polynomial) product of two C-series results in terms
  383. that are not in the Laguerre polynomial basis set. Thus, to express
  384. the product as a Laguerre series, it is necessary to "reproject" the
  385. product onto said basis set, which may produce "unintuitive" (but
  386. correct) results; see Examples section below.
  387. Examples
  388. --------
  389. >>> from numpy.polynomial.laguerre import lagmul
  390. >>> lagmul([1, 2, 3], [0, 1, 2])
  391. array([ 8., -13., 38., -51., 36.])
  392. """
  393. # s1, s2 are trimmed copies
  394. [c1, c2] = pu.as_series([c1, c2])
  395. if len(c1) > len(c2):
  396. c = c2
  397. xs = c1
  398. else:
  399. c = c1
  400. xs = c2
  401. if len(c) == 1:
  402. c0 = c[0]*xs
  403. c1 = 0
  404. elif len(c) == 2:
  405. c0 = c[0]*xs
  406. c1 = c[1]*xs
  407. else:
  408. nd = len(c)
  409. c0 = c[-2]*xs
  410. c1 = c[-1]*xs
  411. for i in range(3, len(c) + 1):
  412. tmp = c0
  413. nd = nd - 1
  414. c0 = lagsub(c[-i]*xs, (c1*(nd - 1))/nd)
  415. c1 = lagadd(tmp, lagsub((2*nd - 1)*c1, lagmulx(c1))/nd)
  416. return lagadd(c0, lagsub(c1, lagmulx(c1)))
  417. def lagdiv(c1, c2):
  418. """
  419. Divide one Laguerre series by another.
  420. Returns the quotient-with-remainder of two Laguerre series
  421. `c1` / `c2`. The arguments are sequences of coefficients from lowest
  422. order "term" to highest, e.g., [1,2,3] represents the series
  423. ``P_0 + 2*P_1 + 3*P_2``.
  424. Parameters
  425. ----------
  426. c1, c2 : array_like
  427. 1-D arrays of Laguerre series coefficients ordered from low to
  428. high.
  429. Returns
  430. -------
  431. [quo, rem] : ndarrays
  432. Of Laguerre series coefficients representing the quotient and
  433. remainder.
  434. See Also
  435. --------
  436. lagadd, lagsub, lagmulx, lagmul, lagpow
  437. Notes
  438. -----
  439. In general, the (polynomial) division of one Laguerre series by another
  440. results in quotient and remainder terms that are not in the Laguerre
  441. polynomial basis set. Thus, to express these results as a Laguerre
  442. series, it is necessary to "reproject" the results onto the Laguerre
  443. basis set, which may produce "unintuitive" (but correct) results; see
  444. Examples section below.
  445. Examples
  446. --------
  447. >>> from numpy.polynomial.laguerre import lagdiv
  448. >>> lagdiv([ 8., -13., 38., -51., 36.], [0, 1, 2])
  449. (array([ 1., 2., 3.]), array([ 0.]))
  450. >>> lagdiv([ 9., -12., 38., -51., 36.], [0, 1, 2])
  451. (array([ 1., 2., 3.]), array([ 1., 1.]))
  452. """
  453. # c1, c2 are trimmed copies
  454. [c1, c2] = pu.as_series([c1, c2])
  455. if c2[-1] == 0:
  456. raise ZeroDivisionError()
  457. lc1 = len(c1)
  458. lc2 = len(c2)
  459. if lc1 < lc2:
  460. return c1[:1]*0, c1
  461. elif lc2 == 1:
  462. return c1/c2[-1], c1[:1]*0
  463. else:
  464. quo = np.empty(lc1 - lc2 + 1, dtype=c1.dtype)
  465. rem = c1
  466. for i in range(lc1 - lc2, - 1, -1):
  467. p = lagmul([0]*i + [1], c2)
  468. q = rem[-1]/p[-1]
  469. rem = rem[:-1] - q*p[:-1]
  470. quo[i] = q
  471. return quo, pu.trimseq(rem)
  472. def lagpow(c, pow, maxpower=16):
  473. """Raise a Laguerre series to a power.
  474. Returns the Laguerre series `c` raised to the power `pow`. The
  475. argument `c` is a sequence of coefficients ordered from low to high.
  476. i.e., [1,2,3] is the series ``P_0 + 2*P_1 + 3*P_2.``
  477. Parameters
  478. ----------
  479. c : array_like
  480. 1-D array of Laguerre series coefficients ordered from low to
  481. high.
  482. pow : integer
  483. Power to which the series will be raised
  484. maxpower : integer, optional
  485. Maximum power allowed. This is mainly to limit growth of the series
  486. to unmanageable size. Default is 16
  487. Returns
  488. -------
  489. coef : ndarray
  490. Laguerre series of power.
  491. See Also
  492. --------
  493. lagadd, lagsub, lagmulx, lagmul, lagdiv
  494. Examples
  495. --------
  496. >>> from numpy.polynomial.laguerre import lagpow
  497. >>> lagpow([1, 2, 3], 2)
  498. array([ 14., -16., 56., -72., 54.])
  499. """
  500. # c is a trimmed copy
  501. [c] = pu.as_series([c])
  502. power = int(pow)
  503. if power != pow or power < 0:
  504. raise ValueError("Power must be a non-negative integer.")
  505. elif maxpower is not None and power > maxpower:
  506. raise ValueError("Power is too large")
  507. elif power == 0:
  508. return np.array([1], dtype=c.dtype)
  509. elif power == 1:
  510. return c
  511. else:
  512. # This can be made more efficient by using powers of two
  513. # in the usual way.
  514. prd = c
  515. for i in range(2, power + 1):
  516. prd = lagmul(prd, c)
  517. return prd
  518. def lagder(c, m=1, scl=1, axis=0):
  519. """
  520. Differentiate a Laguerre series.
  521. Returns the Laguerre series coefficients `c` differentiated `m` times
  522. along `axis`. At each iteration the result is multiplied by `scl` (the
  523. scaling factor is for use in a linear change of variable). The argument
  524. `c` is an array of coefficients from low to high degree along each
  525. axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2``
  526. while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) +
  527. 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is
  528. ``y``.
  529. Parameters
  530. ----------
  531. c : array_like
  532. Array of Laguerre series coefficients. If `c` is multidimensional
  533. the different axis correspond to different variables with the
  534. degree in each axis given by the corresponding index.
  535. m : int, optional
  536. Number of derivatives taken, must be non-negative. (Default: 1)
  537. scl : scalar, optional
  538. Each differentiation is multiplied by `scl`. The end result is
  539. multiplication by ``scl**m``. This is for use in a linear change of
  540. variable. (Default: 1)
  541. axis : int, optional
  542. Axis over which the derivative is taken. (Default: 0).
  543. .. versionadded:: 1.7.0
  544. Returns
  545. -------
  546. der : ndarray
  547. Laguerre series of the derivative.
  548. See Also
  549. --------
  550. lagint
  551. Notes
  552. -----
  553. In general, the result of differentiating a Laguerre series does not
  554. resemble the same operation on a power series. Thus the result of this
  555. function may be "unintuitive," albeit correct; see Examples section
  556. below.
  557. Examples
  558. --------
  559. >>> from numpy.polynomial.laguerre import lagder
  560. >>> lagder([ 1., 1., 1., -3.])
  561. array([ 1., 2., 3.])
  562. >>> lagder([ 1., 0., 0., -4., 3.], m=2)
  563. array([ 1., 2., 3.])
  564. """
  565. c = np.array(c, ndmin=1, copy=1)
  566. if c.dtype.char in '?bBhHiIlLqQpP':
  567. c = c.astype(np.double)
  568. cnt, iaxis = [int(t) for t in [m, axis]]
  569. if cnt != m:
  570. raise ValueError("The order of derivation must be integer")
  571. if cnt < 0:
  572. raise ValueError("The order of derivation must be non-negative")
  573. if iaxis != axis:
  574. raise ValueError("The axis must be integer")
  575. iaxis = normalize_axis_index(iaxis, c.ndim)
  576. if cnt == 0:
  577. return c
  578. c = np.moveaxis(c, iaxis, 0)
  579. n = len(c)
  580. if cnt >= n:
  581. c = c[:1]*0
  582. else:
  583. for i in range(cnt):
  584. n = n - 1
  585. c *= scl
  586. der = np.empty((n,) + c.shape[1:], dtype=c.dtype)
  587. for j in range(n, 1, -1):
  588. der[j - 1] = -c[j]
  589. c[j - 1] += c[j]
  590. der[0] = -c[1]
  591. c = der
  592. c = np.moveaxis(c, 0, iaxis)
  593. return c
  594. def lagint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
  595. """
  596. Integrate a Laguerre series.
  597. Returns the Laguerre series coefficients `c` integrated `m` times from
  598. `lbnd` along `axis`. At each iteration the resulting series is
  599. **multiplied** by `scl` and an integration constant, `k`, is added.
  600. The scaling factor is for use in a linear change of variable. ("Buyer
  601. beware": note that, depending on what one is doing, one may want `scl`
  602. to be the reciprocal of what one might expect; for more information,
  603. see the Notes section below.) The argument `c` is an array of
  604. coefficients from low to high degree along each axis, e.g., [1,2,3]
  605. represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]]
  606. represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) +
  607. 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.
  608. Parameters
  609. ----------
  610. c : array_like
  611. Array of Laguerre series coefficients. If `c` is multidimensional
  612. the different axis correspond to different variables with the
  613. degree in each axis given by the corresponding index.
  614. m : int, optional
  615. Order of integration, must be positive. (Default: 1)
  616. k : {[], list, scalar}, optional
  617. Integration constant(s). The value of the first integral at
  618. ``lbnd`` is the first value in the list, the value of the second
  619. integral at ``lbnd`` is the second value, etc. If ``k == []`` (the
  620. default), all constants are set to zero. If ``m == 1``, a single
  621. scalar can be given instead of a list.
  622. lbnd : scalar, optional
  623. The lower bound of the integral. (Default: 0)
  624. scl : scalar, optional
  625. Following each integration the result is *multiplied* by `scl`
  626. before the integration constant is added. (Default: 1)
  627. axis : int, optional
  628. Axis over which the integral is taken. (Default: 0).
  629. .. versionadded:: 1.7.0
  630. Returns
  631. -------
  632. S : ndarray
  633. Laguerre series coefficients of the integral.
  634. Raises
  635. ------
  636. ValueError
  637. If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or
  638. ``np.ndim(scl) != 0``.
  639. See Also
  640. --------
  641. lagder
  642. Notes
  643. -----
  644. Note that the result of each integration is *multiplied* by `scl`.
  645. Why is this important to note? Say one is making a linear change of
  646. variable :math:`u = ax + b` in an integral relative to `x`. Then
  647. :math:`dx = du/a`, so one will need to set `scl` equal to
  648. :math:`1/a` - perhaps not what one would have first thought.
  649. Also note that, in general, the result of integrating a C-series needs
  650. to be "reprojected" onto the C-series basis set. Thus, typically,
  651. the result of this function is "unintuitive," albeit correct; see
  652. Examples section below.
  653. Examples
  654. --------
  655. >>> from numpy.polynomial.laguerre import lagint
  656. >>> lagint([1,2,3])
  657. array([ 1., 1., 1., -3.])
  658. >>> lagint([1,2,3], m=2)
  659. array([ 1., 0., 0., -4., 3.])
  660. >>> lagint([1,2,3], k=1)
  661. array([ 2., 1., 1., -3.])
  662. >>> lagint([1,2,3], lbnd=-1)
  663. array([ 11.5, 1. , 1. , -3. ])
  664. >>> lagint([1,2], m=2, k=[1,2], lbnd=-1)
  665. array([ 11.16666667, -5. , -3. , 2. ])
  666. """
  667. c = np.array(c, ndmin=1, copy=1)
  668. if c.dtype.char in '?bBhHiIlLqQpP':
  669. c = c.astype(np.double)
  670. if not np.iterable(k):
  671. k = [k]
  672. cnt, iaxis = [int(t) for t in [m, axis]]
  673. if cnt != m:
  674. raise ValueError("The order of integration must be integer")
  675. if cnt < 0:
  676. raise ValueError("The order of integration must be non-negative")
  677. if len(k) > cnt:
  678. raise ValueError("Too many integration constants")
  679. if np.ndim(lbnd) != 0:
  680. raise ValueError("lbnd must be a scalar.")
  681. if np.ndim(scl) != 0:
  682. raise ValueError("scl must be a scalar.")
  683. if iaxis != axis:
  684. raise ValueError("The axis must be integer")
  685. iaxis = normalize_axis_index(iaxis, c.ndim)
  686. if cnt == 0:
  687. return c
  688. c = np.moveaxis(c, iaxis, 0)
  689. k = list(k) + [0]*(cnt - len(k))
  690. for i in range(cnt):
  691. n = len(c)
  692. c *= scl
  693. if n == 1 and np.all(c[0] == 0):
  694. c[0] += k[i]
  695. else:
  696. tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)
  697. tmp[0] = c[0]
  698. tmp[1] = -c[0]
  699. for j in range(1, n):
  700. tmp[j] += c[j]
  701. tmp[j + 1] = -c[j]
  702. tmp[0] += k[i] - lagval(lbnd, tmp)
  703. c = tmp
  704. c = np.moveaxis(c, 0, iaxis)
  705. return c
  706. def lagval(x, c, tensor=True):
  707. """
  708. Evaluate a Laguerre series at points x.
  709. If `c` is of length `n + 1`, this function returns the value:
  710. .. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x)
  711. The parameter `x` is converted to an array only if it is a tuple or a
  712. list, otherwise it is treated as a scalar. In either case, either `x`
  713. or its elements must support multiplication and addition both with
  714. themselves and with the elements of `c`.
  715. If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If
  716. `c` is multidimensional, then the shape of the result depends on the
  717. value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +
  718. x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that
  719. scalars have shape (,).
  720. Trailing zeros in the coefficients will be used in the evaluation, so
  721. they should be avoided if efficiency is a concern.
  722. Parameters
  723. ----------
  724. x : array_like, compatible object
  725. If `x` is a list or tuple, it is converted to an ndarray, otherwise
  726. it is left unchanged and treated as a scalar. In either case, `x`
  727. or its elements must support addition and multiplication with
  728. with themselves and with the elements of `c`.
  729. c : array_like
  730. Array of coefficients ordered so that the coefficients for terms of
  731. degree n are contained in c[n]. If `c` is multidimensional the
  732. remaining indices enumerate multiple polynomials. In the two
  733. dimensional case the coefficients may be thought of as stored in
  734. the columns of `c`.
  735. tensor : boolean, optional
  736. If True, the shape of the coefficient array is extended with ones
  737. on the right, one for each dimension of `x`. Scalars have dimension 0
  738. for this action. The result is that every column of coefficients in
  739. `c` is evaluated for every element of `x`. If False, `x` is broadcast
  740. over the columns of `c` for the evaluation. This keyword is useful
  741. when `c` is multidimensional. The default value is True.
  742. .. versionadded:: 1.7.0
  743. Returns
  744. -------
  745. values : ndarray, algebra_like
  746. The shape of the return value is described above.
  747. See Also
  748. --------
  749. lagval2d, laggrid2d, lagval3d, laggrid3d
  750. Notes
  751. -----
  752. The evaluation uses Clenshaw recursion, aka synthetic division.
  753. Examples
  754. --------
  755. >>> from numpy.polynomial.laguerre import lagval
  756. >>> coef = [1,2,3]
  757. >>> lagval(1, coef)
  758. -0.5
  759. >>> lagval([[1,2],[3,4]], coef)
  760. array([[-0.5, -4. ],
  761. [-4.5, -2. ]])
  762. """
  763. c = np.array(c, ndmin=1, copy=0)
  764. if c.dtype.char in '?bBhHiIlLqQpP':
  765. c = c.astype(np.double)
  766. if isinstance(x, (tuple, list)):
  767. x = np.asarray(x)
  768. if isinstance(x, np.ndarray) and tensor:
  769. c = c.reshape(c.shape + (1,)*x.ndim)
  770. if len(c) == 1:
  771. c0 = c[0]
  772. c1 = 0
  773. elif len(c) == 2:
  774. c0 = c[0]
  775. c1 = c[1]
  776. else:
  777. nd = len(c)
  778. c0 = c[-2]
  779. c1 = c[-1]
  780. for i in range(3, len(c) + 1):
  781. tmp = c0
  782. nd = nd - 1
  783. c0 = c[-i] - (c1*(nd - 1))/nd
  784. c1 = tmp + (c1*((2*nd - 1) - x))/nd
  785. return c0 + c1*(1 - x)
  786. def lagval2d(x, y, c):
  787. """
  788. Evaluate a 2-D Laguerre series at points (x, y).
  789. This function returns the values:
  790. .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y)
  791. The parameters `x` and `y` are converted to arrays only if they are
  792. tuples or a lists, otherwise they are treated as a scalars and they
  793. must have the same shape after conversion. In either case, either `x`
  794. and `y` or their elements must support multiplication and addition both
  795. with themselves and with the elements of `c`.
  796. If `c` is a 1-D array a one is implicitly appended to its shape to make
  797. it 2-D. The shape of the result will be c.shape[2:] + x.shape.
  798. Parameters
  799. ----------
  800. x, y : array_like, compatible objects
  801. The two dimensional series is evaluated at the points `(x, y)`,
  802. where `x` and `y` must have the same shape. If `x` or `y` is a list
  803. or tuple, it is first converted to an ndarray, otherwise it is left
  804. unchanged and if it isn't an ndarray it is treated as a scalar.
  805. c : array_like
  806. Array of coefficients ordered so that the coefficient of the term
  807. of multi-degree i,j is contained in ``c[i,j]``. If `c` has
  808. dimension greater than two the remaining indices enumerate multiple
  809. sets of coefficients.
  810. Returns
  811. -------
  812. values : ndarray, compatible object
  813. The values of the two dimensional polynomial at points formed with
  814. pairs of corresponding values from `x` and `y`.
  815. See Also
  816. --------
  817. lagval, laggrid2d, lagval3d, laggrid3d
  818. Notes
  819. -----
  820. .. versionadded:: 1.7.0
  821. """
  822. try:
  823. x, y = np.array((x, y), copy=0)
  824. except Exception:
  825. raise ValueError('x, y are incompatible')
  826. c = lagval(x, c)
  827. c = lagval(y, c, tensor=False)
  828. return c
  829. def laggrid2d(x, y, c):
  830. """
  831. Evaluate a 2-D Laguerre series on the Cartesian product of x and y.
  832. This function returns the values:
  833. .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b)
  834. where the points `(a, b)` consist of all pairs formed by taking
  835. `a` from `x` and `b` from `y`. The resulting points form a grid with
  836. `x` in the first dimension and `y` in the second.
  837. The parameters `x` and `y` are converted to arrays only if they are
  838. tuples or a lists, otherwise they are treated as a scalars. In either
  839. case, either `x` and `y` or their elements must support multiplication
  840. and addition both with themselves and with the elements of `c`.
  841. If `c` has fewer than two dimensions, ones are implicitly appended to
  842. its shape to make it 2-D. The shape of the result will be c.shape[2:] +
  843. x.shape + y.shape.
  844. Parameters
  845. ----------
  846. x, y : array_like, compatible objects
  847. The two dimensional series is evaluated at the points in the
  848. Cartesian product of `x` and `y`. If `x` or `y` is a list or
  849. tuple, it is first converted to an ndarray, otherwise it is left
  850. unchanged and, if it isn't an ndarray, it is treated as a scalar.
  851. c : array_like
  852. Array of coefficients ordered so that the coefficient of the term of
  853. multi-degree i,j is contained in `c[i,j]`. If `c` has dimension
  854. greater than two the remaining indices enumerate multiple sets of
  855. coefficients.
  856. Returns
  857. -------
  858. values : ndarray, compatible object
  859. The values of the two dimensional Chebyshev series at points in the
  860. Cartesian product of `x` and `y`.
  861. See Also
  862. --------
  863. lagval, lagval2d, lagval3d, laggrid3d
  864. Notes
  865. -----
  866. .. versionadded:: 1.7.0
  867. """
  868. c = lagval(x, c)
  869. c = lagval(y, c)
  870. return c
  871. def lagval3d(x, y, z, c):
  872. """
  873. Evaluate a 3-D Laguerre series at points (x, y, z).
  874. This function returns the values:
  875. .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z)
  876. The parameters `x`, `y`, and `z` are converted to arrays only if
  877. they are tuples or a lists, otherwise they are treated as a scalars and
  878. they must have the same shape after conversion. In either case, either
  879. `x`, `y`, and `z` or their elements must support multiplication and
  880. addition both with themselves and with the elements of `c`.
  881. If `c` has fewer than 3 dimensions, ones are implicitly appended to its
  882. shape to make it 3-D. The shape of the result will be c.shape[3:] +
  883. x.shape.
  884. Parameters
  885. ----------
  886. x, y, z : array_like, compatible object
  887. The three dimensional series is evaluated at the points
  888. `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If
  889. any of `x`, `y`, or `z` is a list or tuple, it is first converted
  890. to an ndarray, otherwise it is left unchanged and if it isn't an
  891. ndarray it is treated as a scalar.
  892. c : array_like
  893. Array of coefficients ordered so that the coefficient of the term of
  894. multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension
  895. greater than 3 the remaining indices enumerate multiple sets of
  896. coefficients.
  897. Returns
  898. -------
  899. values : ndarray, compatible object
  900. The values of the multidimension polynomial on points formed with
  901. triples of corresponding values from `x`, `y`, and `z`.
  902. See Also
  903. --------
  904. lagval, lagval2d, laggrid2d, laggrid3d
  905. Notes
  906. -----
  907. .. versionadded:: 1.7.0
  908. """
  909. try:
  910. x, y, z = np.array((x, y, z), copy=0)
  911. except Exception:
  912. raise ValueError('x, y, z are incompatible')
  913. c = lagval(x, c)
  914. c = lagval(y, c, tensor=False)
  915. c = lagval(z, c, tensor=False)
  916. return c
  917. def laggrid3d(x, y, z, c):
  918. """
  919. Evaluate a 3-D Laguerre series on the Cartesian product of x, y, and z.
  920. This function returns the values:
  921. .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c)
  922. where the points `(a, b, c)` consist of all triples formed by taking
  923. `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form
  924. a grid with `x` in the first dimension, `y` in the second, and `z` in
  925. the third.
  926. The parameters `x`, `y`, and `z` are converted to arrays only if they
  927. are tuples or a lists, otherwise they are treated as a scalars. In
  928. either case, either `x`, `y`, and `z` or their elements must support
  929. multiplication and addition both with themselves and with the elements
  930. of `c`.
  931. If `c` has fewer than three dimensions, ones are implicitly appended to
  932. its shape to make it 3-D. The shape of the result will be c.shape[3:] +
  933. x.shape + y.shape + z.shape.
  934. Parameters
  935. ----------
  936. x, y, z : array_like, compatible objects
  937. The three dimensional series is evaluated at the points in the
  938. Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a
  939. list or tuple, it is first converted to an ndarray, otherwise it is
  940. left unchanged and, if it isn't an ndarray, it is treated as a
  941. scalar.
  942. c : array_like
  943. Array of coefficients ordered so that the coefficients for terms of
  944. degree i,j are contained in ``c[i,j]``. If `c` has dimension
  945. greater than two the remaining indices enumerate multiple sets of
  946. coefficients.
  947. Returns
  948. -------
  949. values : ndarray, compatible object
  950. The values of the two dimensional polynomial at points in the Cartesian
  951. product of `x` and `y`.
  952. See Also
  953. --------
  954. lagval, lagval2d, laggrid2d, lagval3d
  955. Notes
  956. -----
  957. .. versionadded:: 1.7.0
  958. """
  959. c = lagval(x, c)
  960. c = lagval(y, c)
  961. c = lagval(z, c)
  962. return c
  963. def lagvander(x, deg):
  964. """Pseudo-Vandermonde matrix of given degree.
  965. Returns the pseudo-Vandermonde matrix of degree `deg` and sample points
  966. `x`. The pseudo-Vandermonde matrix is defined by
  967. .. math:: V[..., i] = L_i(x)
  968. where `0 <= i <= deg`. The leading indices of `V` index the elements of
  969. `x` and the last index is the degree of the Laguerre polynomial.
  970. If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the
  971. array ``V = lagvander(x, n)``, then ``np.dot(V, c)`` and
  972. ``lagval(x, c)`` are the same up to roundoff. This equivalence is
  973. useful both for least squares fitting and for the evaluation of a large
  974. number of Laguerre series of the same degree and sample points.
  975. Parameters
  976. ----------
  977. x : array_like
  978. Array of points. The dtype is converted to float64 or complex128
  979. depending on whether any of the elements are complex. If `x` is
  980. scalar it is converted to a 1-D array.
  981. deg : int
  982. Degree of the resulting matrix.
  983. Returns
  984. -------
  985. vander : ndarray
  986. The pseudo-Vandermonde matrix. The shape of the returned matrix is
  987. ``x.shape + (deg + 1,)``, where The last index is the degree of the
  988. corresponding Laguerre polynomial. The dtype will be the same as
  989. the converted `x`.
  990. Examples
  991. --------
  992. >>> from numpy.polynomial.laguerre import lagvander
  993. >>> x = np.array([0, 1, 2])
  994. >>> lagvander(x, 3)
  995. array([[ 1. , 1. , 1. , 1. ],
  996. [ 1. , 0. , -0.5 , -0.66666667],
  997. [ 1. , -1. , -1. , -0.33333333]])
  998. """
  999. ideg = int(deg)
  1000. if ideg != deg:
  1001. raise ValueError("deg must be integer")
  1002. if ideg < 0:
  1003. raise ValueError("deg must be non-negative")
  1004. x = np.array(x, copy=0, ndmin=1) + 0.0
  1005. dims = (ideg + 1,) + x.shape
  1006. dtyp = x.dtype
  1007. v = np.empty(dims, dtype=dtyp)
  1008. v[0] = x*0 + 1
  1009. if ideg > 0:
  1010. v[1] = 1 - x
  1011. for i in range(2, ideg + 1):
  1012. v[i] = (v[i-1]*(2*i - 1 - x) - v[i-2]*(i - 1))/i
  1013. return np.moveaxis(v, 0, -1)
  1014. def lagvander2d(x, y, deg):
  1015. """Pseudo-Vandermonde matrix of given degrees.
  1016. Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
  1017. points `(x, y)`. The pseudo-Vandermonde matrix is defined by
  1018. .. math:: V[..., (deg[1] + 1)*i + j] = L_i(x) * L_j(y),
  1019. where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of
  1020. `V` index the points `(x, y)` and the last index encodes the degrees of
  1021. the Laguerre polynomials.
  1022. If ``V = lagvander2d(x, y, [xdeg, ydeg])``, then the columns of `V`
  1023. correspond to the elements of a 2-D coefficient array `c` of shape
  1024. (xdeg + 1, ydeg + 1) in the order
  1025. .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ...
  1026. and ``np.dot(V, c.flat)`` and ``lagval2d(x, y, c)`` will be the same
  1027. up to roundoff. This equivalence is useful both for least squares
  1028. fitting and for the evaluation of a large number of 2-D Laguerre
  1029. series of the same degrees and sample points.
  1030. Parameters
  1031. ----------
  1032. x, y : array_like
  1033. Arrays of point coordinates, all of the same shape. The dtypes
  1034. will be converted to either float64 or complex128 depending on
  1035. whether any of the elements are complex. Scalars are converted to
  1036. 1-D arrays.
  1037. deg : list of ints
  1038. List of maximum degrees of the form [x_deg, y_deg].
  1039. Returns
  1040. -------
  1041. vander2d : ndarray
  1042. The shape of the returned matrix is ``x.shape + (order,)``, where
  1043. :math:`order = (deg[0]+1)*(deg([1]+1)`. The dtype will be the same
  1044. as the converted `x` and `y`.
  1045. See Also
  1046. --------
  1047. lagvander, lagvander3d. lagval2d, lagval3d
  1048. Notes
  1049. -----
  1050. .. versionadded:: 1.7.0
  1051. """
  1052. ideg = [int(d) for d in deg]
  1053. is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)]
  1054. if is_valid != [1, 1]:
  1055. raise ValueError("degrees must be non-negative integers")
  1056. degx, degy = ideg
  1057. x, y = np.array((x, y), copy=0) + 0.0
  1058. vx = lagvander(x, degx)
  1059. vy = lagvander(y, degy)
  1060. v = vx[..., None]*vy[..., None,:]
  1061. return v.reshape(v.shape[:-2] + (-1,))
  1062. def lagvander3d(x, y, z, deg):
  1063. """Pseudo-Vandermonde matrix of given degrees.
  1064. Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
  1065. points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`,
  1066. then The pseudo-Vandermonde matrix is defined by
  1067. .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = L_i(x)*L_j(y)*L_k(z),
  1068. where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading
  1069. indices of `V` index the points `(x, y, z)` and the last index encodes
  1070. the degrees of the Laguerre polynomials.
  1071. If ``V = lagvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns
  1072. of `V` correspond to the elements of a 3-D coefficient array `c` of
  1073. shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order
  1074. .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...
  1075. and ``np.dot(V, c.flat)`` and ``lagval3d(x, y, z, c)`` will be the
  1076. same up to roundoff. This equivalence is useful both for least squares
  1077. fitting and for the evaluation of a large number of 3-D Laguerre
  1078. series of the same degrees and sample points.
  1079. Parameters
  1080. ----------
  1081. x, y, z : array_like
  1082. Arrays of point coordinates, all of the same shape. The dtypes will
  1083. be converted to either float64 or complex128 depending on whether
  1084. any of the elements are complex. Scalars are converted to 1-D
  1085. arrays.
  1086. deg : list of ints
  1087. List of maximum degrees of the form [x_deg, y_deg, z_deg].
  1088. Returns
  1089. -------
  1090. vander3d : ndarray
  1091. The shape of the returned matrix is ``x.shape + (order,)``, where
  1092. :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`. The dtype will
  1093. be the same as the converted `x`, `y`, and `z`.
  1094. See Also
  1095. --------
  1096. lagvander, lagvander3d. lagval2d, lagval3d
  1097. Notes
  1098. -----
  1099. .. versionadded:: 1.7.0
  1100. """
  1101. ideg = [int(d) for d in deg]
  1102. is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)]
  1103. if is_valid != [1, 1, 1]:
  1104. raise ValueError("degrees must be non-negative integers")
  1105. degx, degy, degz = ideg
  1106. x, y, z = np.array((x, y, z), copy=0) + 0.0
  1107. vx = lagvander(x, degx)
  1108. vy = lagvander(y, degy)
  1109. vz = lagvander(z, degz)
  1110. v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:]
  1111. return v.reshape(v.shape[:-3] + (-1,))
  1112. def lagfit(x, y, deg, rcond=None, full=False, w=None):
  1113. """
  1114. Least squares fit of Laguerre series to data.
  1115. Return the coefficients of a Laguerre series of degree `deg` that is the
  1116. least squares fit to the data values `y` given at points `x`. If `y` is
  1117. 1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple
  1118. fits are done, one for each column of `y`, and the resulting
  1119. coefficients are stored in the corresponding columns of a 2-D return.
  1120. The fitted polynomial(s) are in the form
  1121. .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x),
  1122. where `n` is `deg`.
  1123. Parameters
  1124. ----------
  1125. x : array_like, shape (M,)
  1126. x-coordinates of the M sample points ``(x[i], y[i])``.
  1127. y : array_like, shape (M,) or (M, K)
  1128. y-coordinates of the sample points. Several data sets of sample
  1129. points sharing the same x-coordinates can be fitted at once by
  1130. passing in a 2D-array that contains one dataset per column.
  1131. deg : int or 1-D array_like
  1132. Degree(s) of the fitting polynomials. If `deg` is a single integer
  1133. all terms up to and including the `deg`'th term are included in the
  1134. fit. For NumPy versions >= 1.11.0 a list of integers specifying the
  1135. degrees of the terms to include may be used instead.
  1136. rcond : float, optional
  1137. Relative condition number of the fit. Singular values smaller than
  1138. this relative to the largest singular value will be ignored. The
  1139. default value is len(x)*eps, where eps is the relative precision of
  1140. the float type, about 2e-16 in most cases.
  1141. full : bool, optional
  1142. Switch determining nature of return value. When it is False (the
  1143. default) just the coefficients are returned, when True diagnostic
  1144. information from the singular value decomposition is also returned.
  1145. w : array_like, shape (`M`,), optional
  1146. Weights. If not None, the contribution of each point
  1147. ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the
  1148. weights are chosen so that the errors of the products ``w[i]*y[i]``
  1149. all have the same variance. The default value is None.
  1150. Returns
  1151. -------
  1152. coef : ndarray, shape (M,) or (M, K)
  1153. Laguerre coefficients ordered from low to high. If `y` was 2-D,
  1154. the coefficients for the data in column k of `y` are in column
  1155. `k`.
  1156. [residuals, rank, singular_values, rcond] : list
  1157. These values are only returned if `full` = True
  1158. resid -- sum of squared residuals of the least squares fit
  1159. rank -- the numerical rank of the scaled Vandermonde matrix
  1160. sv -- singular values of the scaled Vandermonde matrix
  1161. rcond -- value of `rcond`.
  1162. For more details, see `linalg.lstsq`.
  1163. Warns
  1164. -----
  1165. RankWarning
  1166. The rank of the coefficient matrix in the least-squares fit is
  1167. deficient. The warning is only raised if `full` = False. The
  1168. warnings can be turned off by
  1169. >>> import warnings
  1170. >>> warnings.simplefilter('ignore', RankWarning)
  1171. See Also
  1172. --------
  1173. chebfit, legfit, polyfit, hermfit, hermefit
  1174. lagval : Evaluates a Laguerre series.
  1175. lagvander : pseudo Vandermonde matrix of Laguerre series.
  1176. lagweight : Laguerre weight function.
  1177. linalg.lstsq : Computes a least-squares fit from the matrix.
  1178. scipy.interpolate.UnivariateSpline : Computes spline fits.
  1179. Notes
  1180. -----
  1181. The solution is the coefficients of the Laguerre series `p` that
  1182. minimizes the sum of the weighted squared errors
  1183. .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,
  1184. where the :math:`w_j` are the weights. This problem is solved by
  1185. setting up as the (typically) overdetermined matrix equation
  1186. .. math:: V(x) * c = w * y,
  1187. where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the
  1188. coefficients to be solved for, `w` are the weights, and `y` are the
  1189. observed values. This equation is then solved using the singular value
  1190. decomposition of `V`.
  1191. If some of the singular values of `V` are so small that they are
  1192. neglected, then a `RankWarning` will be issued. This means that the
  1193. coefficient values may be poorly determined. Using a lower order fit
  1194. will usually get rid of the warning. The `rcond` parameter can also be
  1195. set to a value smaller than its default, but the resulting fit may be
  1196. spurious and have large contributions from roundoff error.
  1197. Fits using Laguerre series are probably most useful when the data can
  1198. be approximated by ``sqrt(w(x)) * p(x)``, where `w(x)` is the Laguerre
  1199. weight. In that case the weight ``sqrt(w(x[i])`` should be used
  1200. together with data values ``y[i]/sqrt(w(x[i])``. The weight function is
  1201. available as `lagweight`.
  1202. References
  1203. ----------
  1204. .. [1] Wikipedia, "Curve fitting",
  1205. https://en.wikipedia.org/wiki/Curve_fitting
  1206. Examples
  1207. --------
  1208. >>> from numpy.polynomial.laguerre import lagfit, lagval
  1209. >>> x = np.linspace(0, 10)
  1210. >>> err = np.random.randn(len(x))/10
  1211. >>> y = lagval(x, [1, 2, 3]) + err
  1212. >>> lagfit(x, y, 2)
  1213. array([ 0.96971004, 2.00193749, 3.00288744])
  1214. """
  1215. x = np.asarray(x) + 0.0
  1216. y = np.asarray(y) + 0.0
  1217. deg = np.asarray(deg)
  1218. # check arguments.
  1219. if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0:
  1220. raise TypeError("deg must be an int or non-empty 1-D array of int")
  1221. if deg.min() < 0:
  1222. raise ValueError("expected deg >= 0")
  1223. if x.ndim != 1:
  1224. raise TypeError("expected 1D vector for x")
  1225. if x.size == 0:
  1226. raise TypeError("expected non-empty vector for x")
  1227. if y.ndim < 1 or y.ndim > 2:
  1228. raise TypeError("expected 1D or 2D array for y")
  1229. if len(x) != len(y):
  1230. raise TypeError("expected x and y to have same length")
  1231. if deg.ndim == 0:
  1232. lmax = deg
  1233. order = lmax + 1
  1234. van = lagvander(x, lmax)
  1235. else:
  1236. deg = np.sort(deg)
  1237. lmax = deg[-1]
  1238. order = len(deg)
  1239. van = lagvander(x, lmax)[:, deg]
  1240. # set up the least squares matrices in transposed form
  1241. lhs = van.T
  1242. rhs = y.T
  1243. if w is not None:
  1244. w = np.asarray(w) + 0.0
  1245. if w.ndim != 1:
  1246. raise TypeError("expected 1D vector for w")
  1247. if len(x) != len(w):
  1248. raise TypeError("expected x and w to have same length")
  1249. # apply weights. Don't use inplace operations as they
  1250. # can cause problems with NA.
  1251. lhs = lhs * w
  1252. rhs = rhs * w
  1253. # set rcond
  1254. if rcond is None:
  1255. rcond = len(x)*np.finfo(x.dtype).eps
  1256. # Determine the norms of the design matrix columns.
  1257. if issubclass(lhs.dtype.type, np.complexfloating):
  1258. scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1))
  1259. else:
  1260. scl = np.sqrt(np.square(lhs).sum(1))
  1261. scl[scl == 0] = 1
  1262. # Solve the least squares problem.
  1263. c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond)
  1264. c = (c.T/scl).T
  1265. # Expand c to include non-fitted coefficients which are set to zero
  1266. if deg.ndim > 0:
  1267. if c.ndim == 2:
  1268. cc = np.zeros((lmax+1, c.shape[1]), dtype=c.dtype)
  1269. else:
  1270. cc = np.zeros(lmax+1, dtype=c.dtype)
  1271. cc[deg] = c
  1272. c = cc
  1273. # warn on rank reduction
  1274. if rank != order and not full:
  1275. msg = "The fit may be poorly conditioned"
  1276. warnings.warn(msg, pu.RankWarning, stacklevel=2)
  1277. if full:
  1278. return c, [resids, rank, s, rcond]
  1279. else:
  1280. return c
  1281. def lagcompanion(c):
  1282. """
  1283. Return the companion matrix of c.
  1284. The usual companion matrix of the Laguerre polynomials is already
  1285. symmetric when `c` is a basis Laguerre polynomial, so no scaling is
  1286. applied.
  1287. Parameters
  1288. ----------
  1289. c : array_like
  1290. 1-D array of Laguerre series coefficients ordered from low to high
  1291. degree.
  1292. Returns
  1293. -------
  1294. mat : ndarray
  1295. Companion matrix of dimensions (deg, deg).
  1296. Notes
  1297. -----
  1298. .. versionadded:: 1.7.0
  1299. """
  1300. # c is a trimmed copy
  1301. [c] = pu.as_series([c])
  1302. if len(c) < 2:
  1303. raise ValueError('Series must have maximum degree of at least 1.')
  1304. if len(c) == 2:
  1305. return np.array([[1 + c[0]/c[1]]])
  1306. n = len(c) - 1
  1307. mat = np.zeros((n, n), dtype=c.dtype)
  1308. top = mat.reshape(-1)[1::n+1]
  1309. mid = mat.reshape(-1)[0::n+1]
  1310. bot = mat.reshape(-1)[n::n+1]
  1311. top[...] = -np.arange(1, n)
  1312. mid[...] = 2.*np.arange(n) + 1.
  1313. bot[...] = top
  1314. mat[:, -1] += (c[:-1]/c[-1])*n
  1315. return mat
  1316. def lagroots(c):
  1317. """
  1318. Compute the roots of a Laguerre series.
  1319. Return the roots (a.k.a. "zeros") of the polynomial
  1320. .. math:: p(x) = \\sum_i c[i] * L_i(x).
  1321. Parameters
  1322. ----------
  1323. c : 1-D array_like
  1324. 1-D array of coefficients.
  1325. Returns
  1326. -------
  1327. out : ndarray
  1328. Array of the roots of the series. If all the roots are real,
  1329. then `out` is also real, otherwise it is complex.
  1330. See Also
  1331. --------
  1332. polyroots, legroots, chebroots, hermroots, hermeroots
  1333. Notes
  1334. -----
  1335. The root estimates are obtained as the eigenvalues of the companion
  1336. matrix, Roots far from the origin of the complex plane may have large
  1337. errors due to the numerical instability of the series for such
  1338. values. Roots with multiplicity greater than 1 will also show larger
  1339. errors as the value of the series near such points is relatively
  1340. insensitive to errors in the roots. Isolated roots near the origin can
  1341. be improved by a few iterations of Newton's method.
  1342. The Laguerre series basis polynomials aren't powers of `x` so the
  1343. results of this function may seem unintuitive.
  1344. Examples
  1345. --------
  1346. >>> from numpy.polynomial.laguerre import lagroots, lagfromroots
  1347. >>> coef = lagfromroots([0, 1, 2])
  1348. >>> coef
  1349. array([ 2., -8., 12., -6.])
  1350. >>> lagroots(coef)
  1351. array([ -4.44089210e-16, 1.00000000e+00, 2.00000000e+00])
  1352. """
  1353. # c is a trimmed copy
  1354. [c] = pu.as_series([c])
  1355. if len(c) <= 1:
  1356. return np.array([], dtype=c.dtype)
  1357. if len(c) == 2:
  1358. return np.array([1 + c[0]/c[1]])
  1359. m = lagcompanion(c)
  1360. r = la.eigvals(m)
  1361. r.sort()
  1362. return r
  1363. def laggauss(deg):
  1364. """
  1365. Gauss-Laguerre quadrature.
  1366. Computes the sample points and weights for Gauss-Laguerre quadrature.
  1367. These sample points and weights will correctly integrate polynomials of
  1368. degree :math:`2*deg - 1` or less over the interval :math:`[0, \\inf]`
  1369. with the weight function :math:`f(x) = \\exp(-x)`.
  1370. Parameters
  1371. ----------
  1372. deg : int
  1373. Number of sample points and weights. It must be >= 1.
  1374. Returns
  1375. -------
  1376. x : ndarray
  1377. 1-D ndarray containing the sample points.
  1378. y : ndarray
  1379. 1-D ndarray containing the weights.
  1380. Notes
  1381. -----
  1382. .. versionadded:: 1.7.0
  1383. The results have only been tested up to degree 100 higher degrees may
  1384. be problematic. The weights are determined by using the fact that
  1385. .. math:: w_k = c / (L'_n(x_k) * L_{n-1}(x_k))
  1386. where :math:`c` is a constant independent of :math:`k` and :math:`x_k`
  1387. is the k'th root of :math:`L_n`, and then scaling the results to get
  1388. the right value when integrating 1.
  1389. """
  1390. ideg = int(deg)
  1391. if ideg != deg or ideg < 1:
  1392. raise ValueError("deg must be a non-negative integer")
  1393. # first approximation of roots. We use the fact that the companion
  1394. # matrix is symmetric in this case in order to obtain better zeros.
  1395. c = np.array([0]*deg + [1])
  1396. m = lagcompanion(c)
  1397. x = la.eigvalsh(m)
  1398. # improve roots by one application of Newton
  1399. dy = lagval(x, c)
  1400. df = lagval(x, lagder(c))
  1401. x -= dy/df
  1402. # compute the weights. We scale the factor to avoid possible numerical
  1403. # overflow.
  1404. fm = lagval(x, c[1:])
  1405. fm /= np.abs(fm).max()
  1406. df /= np.abs(df).max()
  1407. w = 1/(fm * df)
  1408. # scale w to get the right value, 1 in this case
  1409. w /= w.sum()
  1410. return x, w
  1411. def lagweight(x):
  1412. """Weight function of the Laguerre polynomials.
  1413. The weight function is :math:`exp(-x)` and the interval of integration
  1414. is :math:`[0, \\inf]`. The Laguerre polynomials are orthogonal, but not
  1415. normalized, with respect to this weight function.
  1416. Parameters
  1417. ----------
  1418. x : array_like
  1419. Values at which the weight function will be computed.
  1420. Returns
  1421. -------
  1422. w : ndarray
  1423. The weight function at `x`.
  1424. Notes
  1425. -----
  1426. .. versionadded:: 1.7.0
  1427. """
  1428. w = np.exp(-x)
  1429. return w
  1430. #
  1431. # Laguerre series class
  1432. #
  1433. class Laguerre(ABCPolyBase):
  1434. """A Laguerre series class.
  1435. The Laguerre class provides the standard Python numerical methods
  1436. '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the
  1437. attributes and methods listed in the `ABCPolyBase` documentation.
  1438. Parameters
  1439. ----------
  1440. coef : array_like
  1441. Laguerre coefficients in order of increasing degree, i.e,
  1442. ``(1, 2, 3)`` gives ``1*L_0(x) + 2*L_1(X) + 3*L_2(x)``.
  1443. domain : (2,) array_like, optional
  1444. Domain to use. The interval ``[domain[0], domain[1]]`` is mapped
  1445. to the interval ``[window[0], window[1]]`` by shifting and scaling.
  1446. The default value is [0, 1].
  1447. window : (2,) array_like, optional
  1448. Window, see `domain` for its use. The default value is [0, 1].
  1449. .. versionadded:: 1.6.0
  1450. """
  1451. # Virtual Functions
  1452. _add = staticmethod(lagadd)
  1453. _sub = staticmethod(lagsub)
  1454. _mul = staticmethod(lagmul)
  1455. _div = staticmethod(lagdiv)
  1456. _pow = staticmethod(lagpow)
  1457. _val = staticmethod(lagval)
  1458. _int = staticmethod(lagint)
  1459. _der = staticmethod(lagder)
  1460. _fit = staticmethod(lagfit)
  1461. _line = staticmethod(lagline)
  1462. _roots = staticmethod(lagroots)
  1463. _fromroots = staticmethod(lagfromroots)
  1464. # Virtual properties
  1465. nickname = 'lag'
  1466. domain = np.array(lagdomain)
  1467. window = np.array(lagdomain)
  1468. basis_name = 'L'