test_legendre.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. """Tests for legendre module.
  2. """
  3. from functools import reduce
  4. import numpy as np
  5. import numpy.polynomial.legendre as leg
  6. from numpy.polynomial.polynomial import polyval
  7. from numpy.testing import (
  8. assert_almost_equal, assert_raises, assert_equal, assert_,
  9. )
  10. L0 = np.array([1])
  11. L1 = np.array([0, 1])
  12. L2 = np.array([-1, 0, 3])/2
  13. L3 = np.array([0, -3, 0, 5])/2
  14. L4 = np.array([3, 0, -30, 0, 35])/8
  15. L5 = np.array([0, 15, 0, -70, 0, 63])/8
  16. L6 = np.array([-5, 0, 105, 0, -315, 0, 231])/16
  17. L7 = np.array([0, -35, 0, 315, 0, -693, 0, 429])/16
  18. L8 = np.array([35, 0, -1260, 0, 6930, 0, -12012, 0, 6435])/128
  19. L9 = np.array([0, 315, 0, -4620, 0, 18018, 0, -25740, 0, 12155])/128
  20. Llist = [L0, L1, L2, L3, L4, L5, L6, L7, L8, L9]
  21. def trim(x):
  22. return leg.legtrim(x, tol=1e-6)
  23. class TestConstants:
  24. def test_legdomain(self):
  25. assert_equal(leg.legdomain, [-1, 1])
  26. def test_legzero(self):
  27. assert_equal(leg.legzero, [0])
  28. def test_legone(self):
  29. assert_equal(leg.legone, [1])
  30. def test_legx(self):
  31. assert_equal(leg.legx, [0, 1])
  32. class TestArithmetic:
  33. x = np.linspace(-1, 1, 100)
  34. def test_legadd(self):
  35. for i in range(5):
  36. for j in range(5):
  37. msg = f"At i={i}, j={j}"
  38. tgt = np.zeros(max(i, j) + 1)
  39. tgt[i] += 1
  40. tgt[j] += 1
  41. res = leg.legadd([0]*i + [1], [0]*j + [1])
  42. assert_equal(trim(res), trim(tgt), err_msg=msg)
  43. def test_legsub(self):
  44. for i in range(5):
  45. for j in range(5):
  46. msg = f"At i={i}, j={j}"
  47. tgt = np.zeros(max(i, j) + 1)
  48. tgt[i] += 1
  49. tgt[j] -= 1
  50. res = leg.legsub([0]*i + [1], [0]*j + [1])
  51. assert_equal(trim(res), trim(tgt), err_msg=msg)
  52. def test_legmulx(self):
  53. assert_equal(leg.legmulx([0]), [0])
  54. assert_equal(leg.legmulx([1]), [0, 1])
  55. for i in range(1, 5):
  56. tmp = 2*i + 1
  57. ser = [0]*i + [1]
  58. tgt = [0]*(i - 1) + [i/tmp, 0, (i + 1)/tmp]
  59. assert_equal(leg.legmulx(ser), tgt)
  60. def test_legmul(self):
  61. # check values of result
  62. for i in range(5):
  63. pol1 = [0]*i + [1]
  64. val1 = leg.legval(self.x, pol1)
  65. for j in range(5):
  66. msg = f"At i={i}, j={j}"
  67. pol2 = [0]*j + [1]
  68. val2 = leg.legval(self.x, pol2)
  69. pol3 = leg.legmul(pol1, pol2)
  70. val3 = leg.legval(self.x, pol3)
  71. assert_(len(pol3) == i + j + 1, msg)
  72. assert_almost_equal(val3, val1*val2, err_msg=msg)
  73. def test_legdiv(self):
  74. for i in range(5):
  75. for j in range(5):
  76. msg = f"At i={i}, j={j}"
  77. ci = [0]*i + [1]
  78. cj = [0]*j + [1]
  79. tgt = leg.legadd(ci, cj)
  80. quo, rem = leg.legdiv(tgt, ci)
  81. res = leg.legadd(leg.legmul(quo, ci), rem)
  82. assert_equal(trim(res), trim(tgt), err_msg=msg)
  83. def test_legpow(self):
  84. for i in range(5):
  85. for j in range(5):
  86. msg = f"At i={i}, j={j}"
  87. c = np.arange(i + 1)
  88. tgt = reduce(leg.legmul, [c]*j, np.array([1]))
  89. res = leg.legpow(c, j)
  90. assert_equal(trim(res), trim(tgt), err_msg=msg)
  91. class TestEvaluation:
  92. # coefficients of 1 + 2*x + 3*x**2
  93. c1d = np.array([2., 2., 2.])
  94. c2d = np.einsum('i,j->ij', c1d, c1d)
  95. c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d)
  96. # some random values in [-1, 1)
  97. x = np.random.random((3, 5))*2 - 1
  98. y = polyval(x, [1., 2., 3.])
  99. def test_legval(self):
  100. #check empty input
  101. assert_equal(leg.legval([], [1]).size, 0)
  102. #check normal input)
  103. x = np.linspace(-1, 1)
  104. y = [polyval(x, c) for c in Llist]
  105. for i in range(10):
  106. msg = f"At i={i}"
  107. tgt = y[i]
  108. res = leg.legval(x, [0]*i + [1])
  109. assert_almost_equal(res, tgt, err_msg=msg)
  110. #check that shape is preserved
  111. for i in range(3):
  112. dims = [2]*i
  113. x = np.zeros(dims)
  114. assert_equal(leg.legval(x, [1]).shape, dims)
  115. assert_equal(leg.legval(x, [1, 0]).shape, dims)
  116. assert_equal(leg.legval(x, [1, 0, 0]).shape, dims)
  117. def test_legval2d(self):
  118. x1, x2, x3 = self.x
  119. y1, y2, y3 = self.y
  120. #test exceptions
  121. assert_raises(ValueError, leg.legval2d, x1, x2[:2], self.c2d)
  122. #test values
  123. tgt = y1*y2
  124. res = leg.legval2d(x1, x2, self.c2d)
  125. assert_almost_equal(res, tgt)
  126. #test shape
  127. z = np.ones((2, 3))
  128. res = leg.legval2d(z, z, self.c2d)
  129. assert_(res.shape == (2, 3))
  130. def test_legval3d(self):
  131. x1, x2, x3 = self.x
  132. y1, y2, y3 = self.y
  133. #test exceptions
  134. assert_raises(ValueError, leg.legval3d, x1, x2, x3[:2], self.c3d)
  135. #test values
  136. tgt = y1*y2*y3
  137. res = leg.legval3d(x1, x2, x3, self.c3d)
  138. assert_almost_equal(res, tgt)
  139. #test shape
  140. z = np.ones((2, 3))
  141. res = leg.legval3d(z, z, z, self.c3d)
  142. assert_(res.shape == (2, 3))
  143. def test_leggrid2d(self):
  144. x1, x2, x3 = self.x
  145. y1, y2, y3 = self.y
  146. #test values
  147. tgt = np.einsum('i,j->ij', y1, y2)
  148. res = leg.leggrid2d(x1, x2, self.c2d)
  149. assert_almost_equal(res, tgt)
  150. #test shape
  151. z = np.ones((2, 3))
  152. res = leg.leggrid2d(z, z, self.c2d)
  153. assert_(res.shape == (2, 3)*2)
  154. def test_leggrid3d(self):
  155. x1, x2, x3 = self.x
  156. y1, y2, y3 = self.y
  157. #test values
  158. tgt = np.einsum('i,j,k->ijk', y1, y2, y3)
  159. res = leg.leggrid3d(x1, x2, x3, self.c3d)
  160. assert_almost_equal(res, tgt)
  161. #test shape
  162. z = np.ones((2, 3))
  163. res = leg.leggrid3d(z, z, z, self.c3d)
  164. assert_(res.shape == (2, 3)*3)
  165. class TestIntegral:
  166. def test_legint(self):
  167. # check exceptions
  168. assert_raises(TypeError, leg.legint, [0], .5)
  169. assert_raises(ValueError, leg.legint, [0], -1)
  170. assert_raises(ValueError, leg.legint, [0], 1, [0, 0])
  171. assert_raises(ValueError, leg.legint, [0], lbnd=[0])
  172. assert_raises(ValueError, leg.legint, [0], scl=[0])
  173. assert_raises(TypeError, leg.legint, [0], axis=.5)
  174. # test integration of zero polynomial
  175. for i in range(2, 5):
  176. k = [0]*(i - 2) + [1]
  177. res = leg.legint([0], m=i, k=k)
  178. assert_almost_equal(res, [0, 1])
  179. # check single integration with integration constant
  180. for i in range(5):
  181. scl = i + 1
  182. pol = [0]*i + [1]
  183. tgt = [i] + [0]*i + [1/scl]
  184. legpol = leg.poly2leg(pol)
  185. legint = leg.legint(legpol, m=1, k=[i])
  186. res = leg.leg2poly(legint)
  187. assert_almost_equal(trim(res), trim(tgt))
  188. # check single integration with integration constant and lbnd
  189. for i in range(5):
  190. scl = i + 1
  191. pol = [0]*i + [1]
  192. legpol = leg.poly2leg(pol)
  193. legint = leg.legint(legpol, m=1, k=[i], lbnd=-1)
  194. assert_almost_equal(leg.legval(-1, legint), i)
  195. # check single integration with integration constant and scaling
  196. for i in range(5):
  197. scl = i + 1
  198. pol = [0]*i + [1]
  199. tgt = [i] + [0]*i + [2/scl]
  200. legpol = leg.poly2leg(pol)
  201. legint = leg.legint(legpol, m=1, k=[i], scl=2)
  202. res = leg.leg2poly(legint)
  203. assert_almost_equal(trim(res), trim(tgt))
  204. # check multiple integrations with default k
  205. for i in range(5):
  206. for j in range(2, 5):
  207. pol = [0]*i + [1]
  208. tgt = pol[:]
  209. for k in range(j):
  210. tgt = leg.legint(tgt, m=1)
  211. res = leg.legint(pol, m=j)
  212. assert_almost_equal(trim(res), trim(tgt))
  213. # check multiple integrations with defined k
  214. for i in range(5):
  215. for j in range(2, 5):
  216. pol = [0]*i + [1]
  217. tgt = pol[:]
  218. for k in range(j):
  219. tgt = leg.legint(tgt, m=1, k=[k])
  220. res = leg.legint(pol, m=j, k=list(range(j)))
  221. assert_almost_equal(trim(res), trim(tgt))
  222. # check multiple integrations with lbnd
  223. for i in range(5):
  224. for j in range(2, 5):
  225. pol = [0]*i + [1]
  226. tgt = pol[:]
  227. for k in range(j):
  228. tgt = leg.legint(tgt, m=1, k=[k], lbnd=-1)
  229. res = leg.legint(pol, m=j, k=list(range(j)), lbnd=-1)
  230. assert_almost_equal(trim(res), trim(tgt))
  231. # check multiple integrations with scaling
  232. for i in range(5):
  233. for j in range(2, 5):
  234. pol = [0]*i + [1]
  235. tgt = pol[:]
  236. for k in range(j):
  237. tgt = leg.legint(tgt, m=1, k=[k], scl=2)
  238. res = leg.legint(pol, m=j, k=list(range(j)), scl=2)
  239. assert_almost_equal(trim(res), trim(tgt))
  240. def test_legint_axis(self):
  241. # check that axis keyword works
  242. c2d = np.random.random((3, 4))
  243. tgt = np.vstack([leg.legint(c) for c in c2d.T]).T
  244. res = leg.legint(c2d, axis=0)
  245. assert_almost_equal(res, tgt)
  246. tgt = np.vstack([leg.legint(c) for c in c2d])
  247. res = leg.legint(c2d, axis=1)
  248. assert_almost_equal(res, tgt)
  249. tgt = np.vstack([leg.legint(c, k=3) for c in c2d])
  250. res = leg.legint(c2d, k=3, axis=1)
  251. assert_almost_equal(res, tgt)
  252. def test_legint_zerointord(self):
  253. assert_equal(leg.legint((1, 2, 3), 0), (1, 2, 3))
  254. class TestDerivative:
  255. def test_legder(self):
  256. # check exceptions
  257. assert_raises(TypeError, leg.legder, [0], .5)
  258. assert_raises(ValueError, leg.legder, [0], -1)
  259. # check that zeroth derivative does nothing
  260. for i in range(5):
  261. tgt = [0]*i + [1]
  262. res = leg.legder(tgt, m=0)
  263. assert_equal(trim(res), trim(tgt))
  264. # check that derivation is the inverse of integration
  265. for i in range(5):
  266. for j in range(2, 5):
  267. tgt = [0]*i + [1]
  268. res = leg.legder(leg.legint(tgt, m=j), m=j)
  269. assert_almost_equal(trim(res), trim(tgt))
  270. # check derivation with scaling
  271. for i in range(5):
  272. for j in range(2, 5):
  273. tgt = [0]*i + [1]
  274. res = leg.legder(leg.legint(tgt, m=j, scl=2), m=j, scl=.5)
  275. assert_almost_equal(trim(res), trim(tgt))
  276. def test_legder_axis(self):
  277. # check that axis keyword works
  278. c2d = np.random.random((3, 4))
  279. tgt = np.vstack([leg.legder(c) for c in c2d.T]).T
  280. res = leg.legder(c2d, axis=0)
  281. assert_almost_equal(res, tgt)
  282. tgt = np.vstack([leg.legder(c) for c in c2d])
  283. res = leg.legder(c2d, axis=1)
  284. assert_almost_equal(res, tgt)
  285. def test_legder_orderhigherthancoeff(self):
  286. c = (1, 2, 3, 4)
  287. assert_equal(leg.legder(c, 4), [0])
  288. class TestVander:
  289. # some random values in [-1, 1)
  290. x = np.random.random((3, 5))*2 - 1
  291. def test_legvander(self):
  292. # check for 1d x
  293. x = np.arange(3)
  294. v = leg.legvander(x, 3)
  295. assert_(v.shape == (3, 4))
  296. for i in range(4):
  297. coef = [0]*i + [1]
  298. assert_almost_equal(v[..., i], leg.legval(x, coef))
  299. # check for 2d x
  300. x = np.array([[1, 2], [3, 4], [5, 6]])
  301. v = leg.legvander(x, 3)
  302. assert_(v.shape == (3, 2, 4))
  303. for i in range(4):
  304. coef = [0]*i + [1]
  305. assert_almost_equal(v[..., i], leg.legval(x, coef))
  306. def test_legvander2d(self):
  307. # also tests polyval2d for non-square coefficient array
  308. x1, x2, x3 = self.x
  309. c = np.random.random((2, 3))
  310. van = leg.legvander2d(x1, x2, [1, 2])
  311. tgt = leg.legval2d(x1, x2, c)
  312. res = np.dot(van, c.flat)
  313. assert_almost_equal(res, tgt)
  314. # check shape
  315. van = leg.legvander2d([x1], [x2], [1, 2])
  316. assert_(van.shape == (1, 5, 6))
  317. def test_legvander3d(self):
  318. # also tests polyval3d for non-square coefficient array
  319. x1, x2, x3 = self.x
  320. c = np.random.random((2, 3, 4))
  321. van = leg.legvander3d(x1, x2, x3, [1, 2, 3])
  322. tgt = leg.legval3d(x1, x2, x3, c)
  323. res = np.dot(van, c.flat)
  324. assert_almost_equal(res, tgt)
  325. # check shape
  326. van = leg.legvander3d([x1], [x2], [x3], [1, 2, 3])
  327. assert_(van.shape == (1, 5, 24))
  328. def test_legvander_negdeg(self):
  329. assert_raises(ValueError, leg.legvander, (1, 2, 3), -1)
  330. class TestFitting:
  331. def test_legfit(self):
  332. def f(x):
  333. return x*(x - 1)*(x - 2)
  334. def f2(x):
  335. return x**4 + x**2 + 1
  336. # Test exceptions
  337. assert_raises(ValueError, leg.legfit, [1], [1], -1)
  338. assert_raises(TypeError, leg.legfit, [[1]], [1], 0)
  339. assert_raises(TypeError, leg.legfit, [], [1], 0)
  340. assert_raises(TypeError, leg.legfit, [1], [[[1]]], 0)
  341. assert_raises(TypeError, leg.legfit, [1, 2], [1], 0)
  342. assert_raises(TypeError, leg.legfit, [1], [1, 2], 0)
  343. assert_raises(TypeError, leg.legfit, [1], [1], 0, w=[[1]])
  344. assert_raises(TypeError, leg.legfit, [1], [1], 0, w=[1, 1])
  345. assert_raises(ValueError, leg.legfit, [1], [1], [-1,])
  346. assert_raises(ValueError, leg.legfit, [1], [1], [2, -1, 6])
  347. assert_raises(TypeError, leg.legfit, [1], [1], [])
  348. # Test fit
  349. x = np.linspace(0, 2)
  350. y = f(x)
  351. #
  352. coef3 = leg.legfit(x, y, 3)
  353. assert_equal(len(coef3), 4)
  354. assert_almost_equal(leg.legval(x, coef3), y)
  355. coef3 = leg.legfit(x, y, [0, 1, 2, 3])
  356. assert_equal(len(coef3), 4)
  357. assert_almost_equal(leg.legval(x, coef3), y)
  358. #
  359. coef4 = leg.legfit(x, y, 4)
  360. assert_equal(len(coef4), 5)
  361. assert_almost_equal(leg.legval(x, coef4), y)
  362. coef4 = leg.legfit(x, y, [0, 1, 2, 3, 4])
  363. assert_equal(len(coef4), 5)
  364. assert_almost_equal(leg.legval(x, coef4), y)
  365. # check things still work if deg is not in strict increasing
  366. coef4 = leg.legfit(x, y, [2, 3, 4, 1, 0])
  367. assert_equal(len(coef4), 5)
  368. assert_almost_equal(leg.legval(x, coef4), y)
  369. #
  370. coef2d = leg.legfit(x, np.array([y, y]).T, 3)
  371. assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
  372. coef2d = leg.legfit(x, np.array([y, y]).T, [0, 1, 2, 3])
  373. assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
  374. # test weighting
  375. w = np.zeros_like(x)
  376. yw = y.copy()
  377. w[1::2] = 1
  378. y[0::2] = 0
  379. wcoef3 = leg.legfit(x, yw, 3, w=w)
  380. assert_almost_equal(wcoef3, coef3)
  381. wcoef3 = leg.legfit(x, yw, [0, 1, 2, 3], w=w)
  382. assert_almost_equal(wcoef3, coef3)
  383. #
  384. wcoef2d = leg.legfit(x, np.array([yw, yw]).T, 3, w=w)
  385. assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
  386. wcoef2d = leg.legfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w)
  387. assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
  388. # test scaling with complex values x points whose square
  389. # is zero when summed.
  390. x = [1, 1j, -1, -1j]
  391. assert_almost_equal(leg.legfit(x, x, 1), [0, 1])
  392. assert_almost_equal(leg.legfit(x, x, [0, 1]), [0, 1])
  393. # test fitting only even Legendre polynomials
  394. x = np.linspace(-1, 1)
  395. y = f2(x)
  396. coef1 = leg.legfit(x, y, 4)
  397. assert_almost_equal(leg.legval(x, coef1), y)
  398. coef2 = leg.legfit(x, y, [0, 2, 4])
  399. assert_almost_equal(leg.legval(x, coef2), y)
  400. assert_almost_equal(coef1, coef2)
  401. class TestCompanion:
  402. def test_raises(self):
  403. assert_raises(ValueError, leg.legcompanion, [])
  404. assert_raises(ValueError, leg.legcompanion, [1])
  405. def test_dimensions(self):
  406. for i in range(1, 5):
  407. coef = [0]*i + [1]
  408. assert_(leg.legcompanion(coef).shape == (i, i))
  409. def test_linear_root(self):
  410. assert_(leg.legcompanion([1, 2])[0, 0] == -.5)
  411. class TestGauss:
  412. def test_100(self):
  413. x, w = leg.leggauss(100)
  414. # test orthogonality. Note that the results need to be normalized,
  415. # otherwise the huge values that can arise from fast growing
  416. # functions like Laguerre can be very confusing.
  417. v = leg.legvander(x, 99)
  418. vv = np.dot(v.T * w, v)
  419. vd = 1/np.sqrt(vv.diagonal())
  420. vv = vd[:, None] * vv * vd
  421. assert_almost_equal(vv, np.eye(100))
  422. # check that the integral of 1 is correct
  423. tgt = 2.0
  424. assert_almost_equal(w.sum(), tgt)
  425. class TestMisc:
  426. def test_legfromroots(self):
  427. res = leg.legfromroots([])
  428. assert_almost_equal(trim(res), [1])
  429. for i in range(1, 5):
  430. roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2])
  431. pol = leg.legfromroots(roots)
  432. res = leg.legval(roots, pol)
  433. tgt = 0
  434. assert_(len(pol) == i + 1)
  435. assert_almost_equal(leg.leg2poly(pol)[-1], 1)
  436. assert_almost_equal(res, tgt)
  437. def test_legroots(self):
  438. assert_almost_equal(leg.legroots([1]), [])
  439. assert_almost_equal(leg.legroots([1, 2]), [-.5])
  440. for i in range(2, 5):
  441. tgt = np.linspace(-1, 1, i)
  442. res = leg.legroots(leg.legfromroots(tgt))
  443. assert_almost_equal(trim(res), trim(tgt))
  444. def test_legtrim(self):
  445. coef = [2, -1, 1, 0]
  446. # Test exceptions
  447. assert_raises(ValueError, leg.legtrim, coef, -1)
  448. # Test results
  449. assert_equal(leg.legtrim(coef), coef[:-1])
  450. assert_equal(leg.legtrim(coef, 1), coef[:-3])
  451. assert_equal(leg.legtrim(coef, 2), [0])
  452. def test_legline(self):
  453. assert_equal(leg.legline(3, 4), [3, 4])
  454. def test_legline_zeroscl(self):
  455. assert_equal(leg.legline(3, 0), [3])
  456. def test_leg2poly(self):
  457. for i in range(10):
  458. assert_almost_equal(leg.leg2poly([0]*i + [1]), Llist[i])
  459. def test_poly2leg(self):
  460. for i in range(10):
  461. assert_almost_equal(leg.poly2leg(Llist[i]), [0]*i + [1])
  462. def test_weight(self):
  463. x = np.linspace(-1, 1, 11)
  464. tgt = 1.
  465. res = leg.legweight(x)
  466. assert_almost_equal(res, tgt)