test_multivariate.py 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675
  1. """
  2. Test functions for multivariate normal distributions.
  3. """
  4. from __future__ import division, print_function, absolute_import
  5. import pickle
  6. from numpy.testing import (assert_allclose, assert_almost_equal,
  7. assert_array_almost_equal, assert_equal,
  8. assert_array_less, assert_)
  9. import pytest
  10. from pytest import raises as assert_raises
  11. from .test_continuous_basic import check_distribution_rvs
  12. import numpy
  13. import numpy as np
  14. import scipy.linalg
  15. from scipy.stats._multivariate import _PSD, _lnB, _cho_inv_batch
  16. from scipy.stats import multivariate_normal
  17. from scipy.stats import matrix_normal
  18. from scipy.stats import special_ortho_group, ortho_group
  19. from scipy.stats import random_correlation
  20. from scipy.stats import unitary_group
  21. from scipy.stats import dirichlet, beta
  22. from scipy.stats import wishart, multinomial, invwishart, chi2, invgamma
  23. from scipy.stats import norm, uniform
  24. from scipy.stats import ks_2samp, kstest
  25. from scipy.stats import binom
  26. from scipy.integrate import romb
  27. from scipy.special import multigammaln
  28. from .common_tests import check_random_state_property
  29. class TestMultivariateNormal(object):
  30. def test_input_shape(self):
  31. mu = np.arange(3)
  32. cov = np.identity(2)
  33. assert_raises(ValueError, multivariate_normal.pdf, (0, 1), mu, cov)
  34. assert_raises(ValueError, multivariate_normal.pdf, (0, 1, 2), mu, cov)
  35. assert_raises(ValueError, multivariate_normal.cdf, (0, 1), mu, cov)
  36. assert_raises(ValueError, multivariate_normal.cdf, (0, 1, 2), mu, cov)
  37. def test_scalar_values(self):
  38. np.random.seed(1234)
  39. # When evaluated on scalar data, the pdf should return a scalar
  40. x, mean, cov = 1.5, 1.7, 2.5
  41. pdf = multivariate_normal.pdf(x, mean, cov)
  42. assert_equal(pdf.ndim, 0)
  43. # When evaluated on a single vector, the pdf should return a scalar
  44. x = np.random.randn(5)
  45. mean = np.random.randn(5)
  46. cov = np.abs(np.random.randn(5)) # Diagonal values for cov. matrix
  47. pdf = multivariate_normal.pdf(x, mean, cov)
  48. assert_equal(pdf.ndim, 0)
  49. # When evaluated on scalar data, the cdf should return a scalar
  50. x, mean, cov = 1.5, 1.7, 2.5
  51. cdf = multivariate_normal.cdf(x, mean, cov)
  52. assert_equal(cdf.ndim, 0)
  53. # When evaluated on a single vector, the cdf should return a scalar
  54. x = np.random.randn(5)
  55. mean = np.random.randn(5)
  56. cov = np.abs(np.random.randn(5)) # Diagonal values for cov. matrix
  57. cdf = multivariate_normal.cdf(x, mean, cov)
  58. assert_equal(cdf.ndim, 0)
  59. def test_logpdf(self):
  60. # Check that the log of the pdf is in fact the logpdf
  61. np.random.seed(1234)
  62. x = np.random.randn(5)
  63. mean = np.random.randn(5)
  64. cov = np.abs(np.random.randn(5))
  65. d1 = multivariate_normal.logpdf(x, mean, cov)
  66. d2 = multivariate_normal.pdf(x, mean, cov)
  67. assert_allclose(d1, np.log(d2))
  68. def test_logpdf_default_values(self):
  69. # Check that the log of the pdf is in fact the logpdf
  70. # with default parameters Mean=None and cov = 1
  71. np.random.seed(1234)
  72. x = np.random.randn(5)
  73. d1 = multivariate_normal.logpdf(x)
  74. d2 = multivariate_normal.pdf(x)
  75. # check whether default values are being used
  76. d3 = multivariate_normal.logpdf(x, None, 1)
  77. d4 = multivariate_normal.pdf(x, None, 1)
  78. assert_allclose(d1, np.log(d2))
  79. assert_allclose(d3, np.log(d4))
  80. def test_logcdf(self):
  81. # Check that the log of the cdf is in fact the logcdf
  82. np.random.seed(1234)
  83. x = np.random.randn(5)
  84. mean = np.random.randn(5)
  85. cov = np.abs(np.random.randn(5))
  86. d1 = multivariate_normal.logcdf(x, mean, cov)
  87. d2 = multivariate_normal.cdf(x, mean, cov)
  88. assert_allclose(d1, np.log(d2))
  89. def test_logcdf_default_values(self):
  90. # Check that the log of the cdf is in fact the logcdf
  91. # with default parameters Mean=None and cov = 1
  92. np.random.seed(1234)
  93. x = np.random.randn(5)
  94. d1 = multivariate_normal.logcdf(x)
  95. d2 = multivariate_normal.cdf(x)
  96. # check whether default values are being used
  97. d3 = multivariate_normal.logcdf(x, None, 1)
  98. d4 = multivariate_normal.cdf(x, None, 1)
  99. assert_allclose(d1, np.log(d2))
  100. assert_allclose(d3, np.log(d4))
  101. def test_rank(self):
  102. # Check that the rank is detected correctly.
  103. np.random.seed(1234)
  104. n = 4
  105. mean = np.random.randn(n)
  106. for expected_rank in range(1, n + 1):
  107. s = np.random.randn(n, expected_rank)
  108. cov = np.dot(s, s.T)
  109. distn = multivariate_normal(mean, cov, allow_singular=True)
  110. assert_equal(distn.cov_info.rank, expected_rank)
  111. def test_degenerate_distributions(self):
  112. def _sample_orthonormal_matrix(n):
  113. M = np.random.randn(n, n)
  114. u, s, v = scipy.linalg.svd(M)
  115. return u
  116. for n in range(1, 5):
  117. x = np.random.randn(n)
  118. for k in range(1, n + 1):
  119. # Sample a small covariance matrix.
  120. s = np.random.randn(k, k)
  121. cov_kk = np.dot(s, s.T)
  122. # Embed the small covariance matrix into a larger low rank matrix.
  123. cov_nn = np.zeros((n, n))
  124. cov_nn[:k, :k] = cov_kk
  125. # Define a rotation of the larger low rank matrix.
  126. u = _sample_orthonormal_matrix(n)
  127. cov_rr = np.dot(u, np.dot(cov_nn, u.T))
  128. y = np.dot(u, x)
  129. # Check some identities.
  130. distn_kk = multivariate_normal(np.zeros(k), cov_kk,
  131. allow_singular=True)
  132. distn_nn = multivariate_normal(np.zeros(n), cov_nn,
  133. allow_singular=True)
  134. distn_rr = multivariate_normal(np.zeros(n), cov_rr,
  135. allow_singular=True)
  136. assert_equal(distn_kk.cov_info.rank, k)
  137. assert_equal(distn_nn.cov_info.rank, k)
  138. assert_equal(distn_rr.cov_info.rank, k)
  139. pdf_kk = distn_kk.pdf(x[:k])
  140. pdf_nn = distn_nn.pdf(x)
  141. pdf_rr = distn_rr.pdf(y)
  142. assert_allclose(pdf_kk, pdf_nn)
  143. assert_allclose(pdf_kk, pdf_rr)
  144. logpdf_kk = distn_kk.logpdf(x[:k])
  145. logpdf_nn = distn_nn.logpdf(x)
  146. logpdf_rr = distn_rr.logpdf(y)
  147. assert_allclose(logpdf_kk, logpdf_nn)
  148. assert_allclose(logpdf_kk, logpdf_rr)
  149. def test_large_pseudo_determinant(self):
  150. # Check that large pseudo-determinants are handled appropriately.
  151. # Construct a singular diagonal covariance matrix
  152. # whose pseudo determinant overflows double precision.
  153. large_total_log = 1000.0
  154. npos = 100
  155. nzero = 2
  156. large_entry = np.exp(large_total_log / npos)
  157. n = npos + nzero
  158. cov = np.zeros((n, n), dtype=float)
  159. np.fill_diagonal(cov, large_entry)
  160. cov[-nzero:, -nzero:] = 0
  161. # Check some determinants.
  162. assert_equal(scipy.linalg.det(cov), 0)
  163. assert_equal(scipy.linalg.det(cov[:npos, :npos]), np.inf)
  164. assert_allclose(np.linalg.slogdet(cov[:npos, :npos]),
  165. (1, large_total_log))
  166. # Check the pseudo-determinant.
  167. psd = _PSD(cov)
  168. assert_allclose(psd.log_pdet, large_total_log)
  169. def test_broadcasting(self):
  170. np.random.seed(1234)
  171. n = 4
  172. # Construct a random covariance matrix.
  173. data = np.random.randn(n, n)
  174. cov = np.dot(data, data.T)
  175. mean = np.random.randn(n)
  176. # Construct an ndarray which can be interpreted as
  177. # a 2x3 array whose elements are random data vectors.
  178. X = np.random.randn(2, 3, n)
  179. # Check that multiple data points can be evaluated at once.
  180. desired_pdf = multivariate_normal.pdf(X, mean, cov)
  181. desired_cdf = multivariate_normal.cdf(X, mean, cov)
  182. for i in range(2):
  183. for j in range(3):
  184. actual = multivariate_normal.pdf(X[i, j], mean, cov)
  185. assert_allclose(actual, desired_pdf[i,j])
  186. # Repeat for cdf
  187. actual = multivariate_normal.cdf(X[i, j], mean, cov)
  188. assert_allclose(actual, desired_cdf[i,j], rtol=1e-3)
  189. def test_normal_1D(self):
  190. # The probability density function for a 1D normal variable should
  191. # agree with the standard normal distribution in scipy.stats.distributions
  192. x = np.linspace(0, 2, 10)
  193. mean, cov = 1.2, 0.9
  194. scale = cov**0.5
  195. d1 = norm.pdf(x, mean, scale)
  196. d2 = multivariate_normal.pdf(x, mean, cov)
  197. assert_allclose(d1, d2)
  198. # The same should hold for the cumulative distribution function
  199. d1 = norm.cdf(x, mean, scale)
  200. d2 = multivariate_normal.cdf(x, mean, cov)
  201. assert_allclose(d1, d2)
  202. def test_marginalization(self):
  203. # Integrating out one of the variables of a 2D Gaussian should
  204. # yield a 1D Gaussian
  205. mean = np.array([2.5, 3.5])
  206. cov = np.array([[.5, 0.2], [0.2, .6]])
  207. n = 2 ** 8 + 1 # Number of samples
  208. delta = 6 / (n - 1) # Grid spacing
  209. v = np.linspace(0, 6, n)
  210. xv, yv = np.meshgrid(v, v)
  211. pos = np.empty((n, n, 2))
  212. pos[:, :, 0] = xv
  213. pos[:, :, 1] = yv
  214. pdf = multivariate_normal.pdf(pos, mean, cov)
  215. # Marginalize over x and y axis
  216. margin_x = romb(pdf, delta, axis=0)
  217. margin_y = romb(pdf, delta, axis=1)
  218. # Compare with standard normal distribution
  219. gauss_x = norm.pdf(v, loc=mean[0], scale=cov[0, 0] ** 0.5)
  220. gauss_y = norm.pdf(v, loc=mean[1], scale=cov[1, 1] ** 0.5)
  221. assert_allclose(margin_x, gauss_x, rtol=1e-2, atol=1e-2)
  222. assert_allclose(margin_y, gauss_y, rtol=1e-2, atol=1e-2)
  223. def test_frozen(self):
  224. # The frozen distribution should agree with the regular one
  225. np.random.seed(1234)
  226. x = np.random.randn(5)
  227. mean = np.random.randn(5)
  228. cov = np.abs(np.random.randn(5))
  229. norm_frozen = multivariate_normal(mean, cov)
  230. assert_allclose(norm_frozen.pdf(x), multivariate_normal.pdf(x, mean, cov))
  231. assert_allclose(norm_frozen.logpdf(x),
  232. multivariate_normal.logpdf(x, mean, cov))
  233. assert_allclose(norm_frozen.cdf(x), multivariate_normal.cdf(x, mean, cov))
  234. assert_allclose(norm_frozen.logcdf(x),
  235. multivariate_normal.logcdf(x, mean, cov))
  236. def test_pseudodet_pinv(self):
  237. # Make sure that pseudo-inverse and pseudo-det agree on cutoff
  238. # Assemble random covariance matrix with large and small eigenvalues
  239. np.random.seed(1234)
  240. n = 7
  241. x = np.random.randn(n, n)
  242. cov = np.dot(x, x.T)
  243. s, u = scipy.linalg.eigh(cov)
  244. s = 0.5 * np.ones(n)
  245. s[0] = 1.0
  246. s[-1] = 1e-7
  247. cov = np.dot(u, np.dot(np.diag(s), u.T))
  248. # Set cond so that the lowest eigenvalue is below the cutoff
  249. cond = 1e-5
  250. psd = _PSD(cov, cond=cond)
  251. psd_pinv = _PSD(psd.pinv, cond=cond)
  252. # Check that the log pseudo-determinant agrees with the sum
  253. # of the logs of all but the smallest eigenvalue
  254. assert_allclose(psd.log_pdet, np.sum(np.log(s[:-1])))
  255. # Check that the pseudo-determinant of the pseudo-inverse
  256. # agrees with 1 / pseudo-determinant
  257. assert_allclose(-psd.log_pdet, psd_pinv.log_pdet)
  258. def test_exception_nonsquare_cov(self):
  259. cov = [[1, 2, 3], [4, 5, 6]]
  260. assert_raises(ValueError, _PSD, cov)
  261. def test_exception_nonfinite_cov(self):
  262. cov_nan = [[1, 0], [0, np.nan]]
  263. assert_raises(ValueError, _PSD, cov_nan)
  264. cov_inf = [[1, 0], [0, np.inf]]
  265. assert_raises(ValueError, _PSD, cov_inf)
  266. def test_exception_non_psd_cov(self):
  267. cov = [[1, 0], [0, -1]]
  268. assert_raises(ValueError, _PSD, cov)
  269. def test_exception_singular_cov(self):
  270. np.random.seed(1234)
  271. x = np.random.randn(5)
  272. mean = np.random.randn(5)
  273. cov = np.ones((5, 5))
  274. e = np.linalg.LinAlgError
  275. assert_raises(e, multivariate_normal, mean, cov)
  276. assert_raises(e, multivariate_normal.pdf, x, mean, cov)
  277. assert_raises(e, multivariate_normal.logpdf, x, mean, cov)
  278. assert_raises(e, multivariate_normal.cdf, x, mean, cov)
  279. assert_raises(e, multivariate_normal.logcdf, x, mean, cov)
  280. def test_R_values(self):
  281. # Compare the multivariate pdf with some values precomputed
  282. # in R version 3.0.1 (2013-05-16) on Mac OS X 10.6.
  283. # The values below were generated by the following R-script:
  284. # > library(mnormt)
  285. # > x <- seq(0, 2, length=5)
  286. # > y <- 3*x - 2
  287. # > z <- x + cos(y)
  288. # > mu <- c(1, 3, 2)
  289. # > Sigma <- matrix(c(1,2,0,2,5,0.5,0,0.5,3), 3, 3)
  290. # > r_pdf <- dmnorm(cbind(x,y,z), mu, Sigma)
  291. r_pdf = np.array([0.0002214706, 0.0013819953, 0.0049138692,
  292. 0.0103803050, 0.0140250800])
  293. x = np.linspace(0, 2, 5)
  294. y = 3 * x - 2
  295. z = x + np.cos(y)
  296. r = np.array([x, y, z]).T
  297. mean = np.array([1, 3, 2], 'd')
  298. cov = np.array([[1, 2, 0], [2, 5, .5], [0, .5, 3]], 'd')
  299. pdf = multivariate_normal.pdf(r, mean, cov)
  300. assert_allclose(pdf, r_pdf, atol=1e-10)
  301. # Compare the multivariate cdf with some values precomputed
  302. # in R version 3.3.2 (2016-10-31) on Debian GNU/Linux.
  303. # The values below were generated by the following R-script:
  304. # > library(mnormt)
  305. # > x <- seq(0, 2, length=5)
  306. # > y <- 3*x - 2
  307. # > z <- x + cos(y)
  308. # > mu <- c(1, 3, 2)
  309. # > Sigma <- matrix(c(1,2,0,2,5,0.5,0,0.5,3), 3, 3)
  310. # > r_cdf <- pmnorm(cbind(x,y,z), mu, Sigma)
  311. r_cdf = np.array([0.0017866215, 0.0267142892, 0.0857098761,
  312. 0.1063242573, 0.2501068509])
  313. cdf = multivariate_normal.cdf(r, mean, cov)
  314. assert_allclose(cdf, r_cdf, atol=1e-5)
  315. # Also test bivariate cdf with some values precomputed
  316. # in R version 3.3.2 (2016-10-31) on Debian GNU/Linux.
  317. # The values below were generated by the following R-script:
  318. # > library(mnormt)
  319. # > x <- seq(0, 2, length=5)
  320. # > y <- 3*x - 2
  321. # > mu <- c(1, 3)
  322. # > Sigma <- matrix(c(1,2,2,5), 2, 2)
  323. # > r_cdf2 <- pmnorm(cbind(x,y), mu, Sigma)
  324. r_cdf2 = np.array([0.01262147, 0.05838989, 0.18389571,
  325. 0.40696599, 0.66470577])
  326. r2 = np.array([x, y]).T
  327. mean2 = np.array([1, 3], 'd')
  328. cov2 = np.array([[1, 2], [2, 5]], 'd')
  329. cdf2 = multivariate_normal.cdf(r2, mean2, cov2)
  330. assert_allclose(cdf2, r_cdf2, atol=1e-5)
  331. def test_multivariate_normal_rvs_zero_covariance(self):
  332. mean = np.zeros(2)
  333. covariance = np.zeros((2, 2))
  334. model = multivariate_normal(mean, covariance, allow_singular=True)
  335. sample = model.rvs()
  336. assert_equal(sample, [0, 0])
  337. def test_rvs_shape(self):
  338. # Check that rvs parses the mean and covariance correctly, and returns
  339. # an array of the right shape
  340. N = 300
  341. d = 4
  342. sample = multivariate_normal.rvs(mean=np.zeros(d), cov=1, size=N)
  343. assert_equal(sample.shape, (N, d))
  344. sample = multivariate_normal.rvs(mean=None,
  345. cov=np.array([[2, .1], [.1, 1]]),
  346. size=N)
  347. assert_equal(sample.shape, (N, 2))
  348. u = multivariate_normal(mean=0, cov=1)
  349. sample = u.rvs(N)
  350. assert_equal(sample.shape, (N, ))
  351. def test_large_sample(self):
  352. # Generate large sample and compare sample mean and sample covariance
  353. # with mean and covariance matrix.
  354. np.random.seed(2846)
  355. n = 3
  356. mean = np.random.randn(n)
  357. M = np.random.randn(n, n)
  358. cov = np.dot(M, M.T)
  359. size = 5000
  360. sample = multivariate_normal.rvs(mean, cov, size)
  361. assert_allclose(numpy.cov(sample.T), cov, rtol=1e-1)
  362. assert_allclose(sample.mean(0), mean, rtol=1e-1)
  363. def test_entropy(self):
  364. np.random.seed(2846)
  365. n = 3
  366. mean = np.random.randn(n)
  367. M = np.random.randn(n, n)
  368. cov = np.dot(M, M.T)
  369. rv = multivariate_normal(mean, cov)
  370. # Check that frozen distribution agrees with entropy function
  371. assert_almost_equal(rv.entropy(), multivariate_normal.entropy(mean, cov))
  372. # Compare entropy with manually computed expression involving
  373. # the sum of the logs of the eigenvalues of the covariance matrix
  374. eigs = np.linalg.eig(cov)[0]
  375. desired = 1 / 2 * (n * (np.log(2 * np.pi) + 1) + np.sum(np.log(eigs)))
  376. assert_almost_equal(desired, rv.entropy())
  377. def test_lnB(self):
  378. alpha = np.array([1, 1, 1])
  379. desired = .5 # e^lnB = 1/2 for [1, 1, 1]
  380. assert_almost_equal(np.exp(_lnB(alpha)), desired)
  381. class TestMatrixNormal(object):
  382. def test_bad_input(self):
  383. # Check that bad inputs raise errors
  384. num_rows = 4
  385. num_cols = 3
  386. M = 0.3 * np.ones((num_rows,num_cols))
  387. U = 0.5 * np.identity(num_rows) + 0.5 * np.ones((num_rows, num_rows))
  388. V = 0.7 * np.identity(num_cols) + 0.3 * np.ones((num_cols, num_cols))
  389. # Incorrect dimensions
  390. assert_raises(ValueError, matrix_normal, np.zeros((5,4,3)))
  391. assert_raises(ValueError, matrix_normal, M, np.zeros(10), V)
  392. assert_raises(ValueError, matrix_normal, M, U, np.zeros(10))
  393. assert_raises(ValueError, matrix_normal, M, U, U)
  394. assert_raises(ValueError, matrix_normal, M, V, V)
  395. assert_raises(ValueError, matrix_normal, M.T, U, V)
  396. # Singular covariance
  397. e = np.linalg.LinAlgError
  398. assert_raises(e, matrix_normal, M, U, np.ones((num_cols, num_cols)))
  399. assert_raises(e, matrix_normal, M, np.ones((num_rows, num_rows)), V)
  400. def test_default_inputs(self):
  401. # Check that default argument handling works
  402. num_rows = 4
  403. num_cols = 3
  404. M = 0.3 * np.ones((num_rows,num_cols))
  405. U = 0.5 * np.identity(num_rows) + 0.5 * np.ones((num_rows, num_rows))
  406. V = 0.7 * np.identity(num_cols) + 0.3 * np.ones((num_cols, num_cols))
  407. Z = np.zeros((num_rows, num_cols))
  408. Zr = np.zeros((num_rows, 1))
  409. Zc = np.zeros((1, num_cols))
  410. Ir = np.identity(num_rows)
  411. Ic = np.identity(num_cols)
  412. I1 = np.identity(1)
  413. assert_equal(matrix_normal.rvs(mean=M, rowcov=U, colcov=V).shape,
  414. (num_rows, num_cols))
  415. assert_equal(matrix_normal.rvs(mean=M).shape,
  416. (num_rows, num_cols))
  417. assert_equal(matrix_normal.rvs(rowcov=U).shape,
  418. (num_rows, 1))
  419. assert_equal(matrix_normal.rvs(colcov=V).shape,
  420. (1, num_cols))
  421. assert_equal(matrix_normal.rvs(mean=M, colcov=V).shape,
  422. (num_rows, num_cols))
  423. assert_equal(matrix_normal.rvs(mean=M, rowcov=U).shape,
  424. (num_rows, num_cols))
  425. assert_equal(matrix_normal.rvs(rowcov=U, colcov=V).shape,
  426. (num_rows, num_cols))
  427. assert_equal(matrix_normal(mean=M).rowcov, Ir)
  428. assert_equal(matrix_normal(mean=M).colcov, Ic)
  429. assert_equal(matrix_normal(rowcov=U).mean, Zr)
  430. assert_equal(matrix_normal(rowcov=U).colcov, I1)
  431. assert_equal(matrix_normal(colcov=V).mean, Zc)
  432. assert_equal(matrix_normal(colcov=V).rowcov, I1)
  433. assert_equal(matrix_normal(mean=M, rowcov=U).colcov, Ic)
  434. assert_equal(matrix_normal(mean=M, colcov=V).rowcov, Ir)
  435. assert_equal(matrix_normal(rowcov=U, colcov=V).mean, Z)
  436. def test_covariance_expansion(self):
  437. # Check that covariance can be specified with scalar or vector
  438. num_rows = 4
  439. num_cols = 3
  440. M = 0.3 * np.ones((num_rows,num_cols))
  441. Uv = 0.2*np.ones(num_rows)
  442. Us = 0.2
  443. Vv = 0.1*np.ones(num_cols)
  444. Vs = 0.1
  445. Ir = np.identity(num_rows)
  446. Ic = np.identity(num_cols)
  447. assert_equal(matrix_normal(mean=M, rowcov=Uv, colcov=Vv).rowcov,
  448. 0.2*Ir)
  449. assert_equal(matrix_normal(mean=M, rowcov=Uv, colcov=Vv).colcov,
  450. 0.1*Ic)
  451. assert_equal(matrix_normal(mean=M, rowcov=Us, colcov=Vs).rowcov,
  452. 0.2*Ir)
  453. assert_equal(matrix_normal(mean=M, rowcov=Us, colcov=Vs).colcov,
  454. 0.1*Ic)
  455. def test_frozen_matrix_normal(self):
  456. for i in range(1,5):
  457. for j in range(1,5):
  458. M = 0.3 * np.ones((i,j))
  459. U = 0.5 * np.identity(i) + 0.5 * np.ones((i,i))
  460. V = 0.7 * np.identity(j) + 0.3 * np.ones((j,j))
  461. frozen = matrix_normal(mean=M, rowcov=U, colcov=V)
  462. rvs1 = frozen.rvs(random_state=1234)
  463. rvs2 = matrix_normal.rvs(mean=M, rowcov=U, colcov=V,
  464. random_state=1234)
  465. assert_equal(rvs1, rvs2)
  466. X = frozen.rvs(random_state=1234)
  467. pdf1 = frozen.pdf(X)
  468. pdf2 = matrix_normal.pdf(X, mean=M, rowcov=U, colcov=V)
  469. assert_equal(pdf1, pdf2)
  470. logpdf1 = frozen.logpdf(X)
  471. logpdf2 = matrix_normal.logpdf(X, mean=M, rowcov=U, colcov=V)
  472. assert_equal(logpdf1, logpdf2)
  473. def test_matches_multivariate(self):
  474. # Check that the pdfs match those obtained by vectorising and
  475. # treating as a multivariate normal.
  476. for i in range(1,5):
  477. for j in range(1,5):
  478. M = 0.3 * np.ones((i,j))
  479. U = 0.5 * np.identity(i) + 0.5 * np.ones((i,i))
  480. V = 0.7 * np.identity(j) + 0.3 * np.ones((j,j))
  481. frozen = matrix_normal(mean=M, rowcov=U, colcov=V)
  482. X = frozen.rvs(random_state=1234)
  483. pdf1 = frozen.pdf(X)
  484. logpdf1 = frozen.logpdf(X)
  485. vecX = X.T.flatten()
  486. vecM = M.T.flatten()
  487. cov = np.kron(V,U)
  488. pdf2 = multivariate_normal.pdf(vecX, mean=vecM, cov=cov)
  489. logpdf2 = multivariate_normal.logpdf(vecX, mean=vecM, cov=cov)
  490. assert_allclose(pdf1, pdf2, rtol=1E-10)
  491. assert_allclose(logpdf1, logpdf2, rtol=1E-10)
  492. def test_array_input(self):
  493. # Check array of inputs has the same output as the separate entries.
  494. num_rows = 4
  495. num_cols = 3
  496. M = 0.3 * np.ones((num_rows,num_cols))
  497. U = 0.5 * np.identity(num_rows) + 0.5 * np.ones((num_rows, num_rows))
  498. V = 0.7 * np.identity(num_cols) + 0.3 * np.ones((num_cols, num_cols))
  499. N = 10
  500. frozen = matrix_normal(mean=M, rowcov=U, colcov=V)
  501. X1 = frozen.rvs(size=N, random_state=1234)
  502. X2 = frozen.rvs(size=N, random_state=4321)
  503. X = np.concatenate((X1[np.newaxis,:,:,:],X2[np.newaxis,:,:,:]), axis=0)
  504. assert_equal(X.shape, (2, N, num_rows, num_cols))
  505. array_logpdf = frozen.logpdf(X)
  506. assert_equal(array_logpdf.shape, (2, N))
  507. for i in range(2):
  508. for j in range(N):
  509. separate_logpdf = matrix_normal.logpdf(X[i,j], mean=M,
  510. rowcov=U, colcov=V)
  511. assert_allclose(separate_logpdf, array_logpdf[i,j], 1E-10)
  512. def test_moments(self):
  513. # Check that the sample moments match the parameters
  514. num_rows = 4
  515. num_cols = 3
  516. M = 0.3 * np.ones((num_rows,num_cols))
  517. U = 0.5 * np.identity(num_rows) + 0.5 * np.ones((num_rows, num_rows))
  518. V = 0.7 * np.identity(num_cols) + 0.3 * np.ones((num_cols, num_cols))
  519. N = 1000
  520. frozen = matrix_normal(mean=M, rowcov=U, colcov=V)
  521. X = frozen.rvs(size=N, random_state=1234)
  522. sample_mean = np.mean(X,axis=0)
  523. assert_allclose(sample_mean, M, atol=0.1)
  524. sample_colcov = np.cov(X.reshape(N*num_rows,num_cols).T)
  525. assert_allclose(sample_colcov, V, atol=0.1)
  526. sample_rowcov = np.cov(np.swapaxes(X,1,2).reshape(
  527. N*num_cols,num_rows).T)
  528. assert_allclose(sample_rowcov, U, atol=0.1)
  529. class TestDirichlet(object):
  530. def test_frozen_dirichlet(self):
  531. np.random.seed(2846)
  532. n = np.random.randint(1, 32)
  533. alpha = np.random.uniform(10e-10, 100, n)
  534. d = dirichlet(alpha)
  535. assert_equal(d.var(), dirichlet.var(alpha))
  536. assert_equal(d.mean(), dirichlet.mean(alpha))
  537. assert_equal(d.entropy(), dirichlet.entropy(alpha))
  538. num_tests = 10
  539. for i in range(num_tests):
  540. x = np.random.uniform(10e-10, 100, n)
  541. x /= np.sum(x)
  542. assert_equal(d.pdf(x[:-1]), dirichlet.pdf(x[:-1], alpha))
  543. assert_equal(d.logpdf(x[:-1]), dirichlet.logpdf(x[:-1], alpha))
  544. def test_numpy_rvs_shape_compatibility(self):
  545. np.random.seed(2846)
  546. alpha = np.array([1.0, 2.0, 3.0])
  547. x = np.random.dirichlet(alpha, size=7)
  548. assert_equal(x.shape, (7, 3))
  549. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  550. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  551. dirichlet.pdf(x.T, alpha)
  552. dirichlet.pdf(x.T[:-1], alpha)
  553. dirichlet.logpdf(x.T, alpha)
  554. dirichlet.logpdf(x.T[:-1], alpha)
  555. def test_alpha_with_zeros(self):
  556. np.random.seed(2846)
  557. alpha = [1.0, 0.0, 3.0]
  558. # don't pass invalid alpha to np.random.dirichlet
  559. x = np.random.dirichlet(np.maximum(1e-9, alpha), size=7).T
  560. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  561. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  562. def test_alpha_with_negative_entries(self):
  563. np.random.seed(2846)
  564. alpha = [1.0, -2.0, 3.0]
  565. # don't pass invalid alpha to np.random.dirichlet
  566. x = np.random.dirichlet(np.maximum(1e-9, alpha), size=7).T
  567. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  568. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  569. def test_data_with_zeros(self):
  570. alpha = np.array([1.0, 2.0, 3.0, 4.0])
  571. x = np.array([0.1, 0.0, 0.2, 0.7])
  572. dirichlet.pdf(x, alpha)
  573. dirichlet.logpdf(x, alpha)
  574. alpha = np.array([1.0, 1.0, 1.0, 1.0])
  575. assert_almost_equal(dirichlet.pdf(x, alpha), 6)
  576. assert_almost_equal(dirichlet.logpdf(x, alpha), np.log(6))
  577. def test_data_with_zeros_and_small_alpha(self):
  578. alpha = np.array([1.0, 0.5, 3.0, 4.0])
  579. x = np.array([0.1, 0.0, 0.2, 0.7])
  580. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  581. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  582. def test_data_with_negative_entries(self):
  583. alpha = np.array([1.0, 2.0, 3.0, 4.0])
  584. x = np.array([0.1, -0.1, 0.3, 0.7])
  585. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  586. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  587. def test_data_with_too_large_entries(self):
  588. alpha = np.array([1.0, 2.0, 3.0, 4.0])
  589. x = np.array([0.1, 1.1, 0.3, 0.7])
  590. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  591. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  592. def test_data_too_deep_c(self):
  593. alpha = np.array([1.0, 2.0, 3.0])
  594. x = np.ones((2, 7, 7)) / 14
  595. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  596. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  597. def test_alpha_too_deep(self):
  598. alpha = np.array([[1.0, 2.0], [3.0, 4.0]])
  599. x = np.ones((2, 2, 7)) / 4
  600. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  601. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  602. def test_alpha_correct_depth(self):
  603. alpha = np.array([1.0, 2.0, 3.0])
  604. x = np.ones((3, 7)) / 3
  605. dirichlet.pdf(x, alpha)
  606. dirichlet.logpdf(x, alpha)
  607. def test_non_simplex_data(self):
  608. alpha = np.array([1.0, 2.0, 3.0])
  609. x = np.ones((3, 7)) / 2
  610. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  611. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  612. def test_data_vector_too_short(self):
  613. alpha = np.array([1.0, 2.0, 3.0, 4.0])
  614. x = np.ones((2, 7)) / 2
  615. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  616. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  617. def test_data_vector_too_long(self):
  618. alpha = np.array([1.0, 2.0, 3.0, 4.0])
  619. x = np.ones((5, 7)) / 5
  620. assert_raises(ValueError, dirichlet.pdf, x, alpha)
  621. assert_raises(ValueError, dirichlet.logpdf, x, alpha)
  622. def test_mean_and_var(self):
  623. alpha = np.array([1., 0.8, 0.2])
  624. d = dirichlet(alpha)
  625. expected_var = [1. / 12., 0.08, 0.03]
  626. expected_mean = [0.5, 0.4, 0.1]
  627. assert_array_almost_equal(d.var(), expected_var)
  628. assert_array_almost_equal(d.mean(), expected_mean)
  629. def test_scalar_values(self):
  630. alpha = np.array([0.2])
  631. d = dirichlet(alpha)
  632. # For alpha of length 1, mean and var should be scalar instead of array
  633. assert_equal(d.mean().ndim, 0)
  634. assert_equal(d.var().ndim, 0)
  635. assert_equal(d.pdf([1.]).ndim, 0)
  636. assert_equal(d.logpdf([1.]).ndim, 0)
  637. def test_K_and_K_minus_1_calls_equal(self):
  638. # Test that calls with K and K-1 entries yield the same results.
  639. np.random.seed(2846)
  640. n = np.random.randint(1, 32)
  641. alpha = np.random.uniform(10e-10, 100, n)
  642. d = dirichlet(alpha)
  643. num_tests = 10
  644. for i in range(num_tests):
  645. x = np.random.uniform(10e-10, 100, n)
  646. x /= np.sum(x)
  647. assert_almost_equal(d.pdf(x[:-1]), d.pdf(x))
  648. def test_multiple_entry_calls(self):
  649. # Test that calls with multiple x vectors as matrix work
  650. np.random.seed(2846)
  651. n = np.random.randint(1, 32)
  652. alpha = np.random.uniform(10e-10, 100, n)
  653. d = dirichlet(alpha)
  654. num_tests = 10
  655. num_multiple = 5
  656. xm = None
  657. for i in range(num_tests):
  658. for m in range(num_multiple):
  659. x = np.random.uniform(10e-10, 100, n)
  660. x /= np.sum(x)
  661. if xm is not None:
  662. xm = np.vstack((xm, x))
  663. else:
  664. xm = x
  665. rm = d.pdf(xm.T)
  666. rs = None
  667. for xs in xm:
  668. r = d.pdf(xs)
  669. if rs is not None:
  670. rs = np.append(rs, r)
  671. else:
  672. rs = r
  673. assert_array_almost_equal(rm, rs)
  674. def test_2D_dirichlet_is_beta(self):
  675. np.random.seed(2846)
  676. alpha = np.random.uniform(10e-10, 100, 2)
  677. d = dirichlet(alpha)
  678. b = beta(alpha[0], alpha[1])
  679. num_tests = 10
  680. for i in range(num_tests):
  681. x = np.random.uniform(10e-10, 100, 2)
  682. x /= np.sum(x)
  683. assert_almost_equal(b.pdf(x), d.pdf([x]))
  684. assert_almost_equal(b.mean(), d.mean()[0])
  685. assert_almost_equal(b.var(), d.var()[0])
  686. def test_multivariate_normal_dimensions_mismatch():
  687. # Regression test for GH #3493. Check that setting up a PDF with a mean of
  688. # length M and a covariance matrix of size (N, N), where M != N, raises a
  689. # ValueError with an informative error message.
  690. mu = np.array([0.0, 0.0])
  691. sigma = np.array([[1.0]])
  692. assert_raises(ValueError, multivariate_normal, mu, sigma)
  693. # A simple check that the right error message was passed along. Checking
  694. # that the entire message is there, word for word, would be somewhat
  695. # fragile, so we just check for the leading part.
  696. try:
  697. multivariate_normal(mu, sigma)
  698. except ValueError as e:
  699. msg = "Dimension mismatch"
  700. assert_equal(str(e)[:len(msg)], msg)
  701. class TestWishart(object):
  702. def test_scale_dimensions(self):
  703. # Test that we can call the Wishart with various scale dimensions
  704. # Test case: dim=1, scale=1
  705. true_scale = np.array(1, ndmin=2)
  706. scales = [
  707. 1, # scalar
  708. [1], # iterable
  709. np.array(1), # 0-dim
  710. np.r_[1], # 1-dim
  711. np.array(1, ndmin=2) # 2-dim
  712. ]
  713. for scale in scales:
  714. w = wishart(1, scale)
  715. assert_equal(w.scale, true_scale)
  716. assert_equal(w.scale.shape, true_scale.shape)
  717. # Test case: dim=2, scale=[[1,0]
  718. # [0,2]
  719. true_scale = np.array([[1,0],
  720. [0,2]])
  721. scales = [
  722. [1,2], # iterable
  723. np.r_[1,2], # 1-dim
  724. np.array([[1,0], # 2-dim
  725. [0,2]])
  726. ]
  727. for scale in scales:
  728. w = wishart(2, scale)
  729. assert_equal(w.scale, true_scale)
  730. assert_equal(w.scale.shape, true_scale.shape)
  731. # We cannot call with a df < dim
  732. assert_raises(ValueError, wishart, 1, np.eye(2))
  733. # We cannot call with a 3-dimension array
  734. scale = np.array(1, ndmin=3)
  735. assert_raises(ValueError, wishart, 1, scale)
  736. def test_quantile_dimensions(self):
  737. # Test that we can call the Wishart rvs with various quantile dimensions
  738. # If dim == 1, consider x.shape = [1,1,1]
  739. X = [
  740. 1, # scalar
  741. [1], # iterable
  742. np.array(1), # 0-dim
  743. np.r_[1], # 1-dim
  744. np.array(1, ndmin=2), # 2-dim
  745. np.array([1], ndmin=3) # 3-dim
  746. ]
  747. w = wishart(1,1)
  748. density = w.pdf(np.array(1, ndmin=3))
  749. for x in X:
  750. assert_equal(w.pdf(x), density)
  751. # If dim == 1, consider x.shape = [1,1,*]
  752. X = [
  753. [1,2,3], # iterable
  754. np.r_[1,2,3], # 1-dim
  755. np.array([1,2,3], ndmin=3) # 3-dim
  756. ]
  757. w = wishart(1,1)
  758. density = w.pdf(np.array([1,2,3], ndmin=3))
  759. for x in X:
  760. assert_equal(w.pdf(x), density)
  761. # If dim == 2, consider x.shape = [2,2,1]
  762. # where x[:,:,*] = np.eye(1)*2
  763. X = [
  764. 2, # scalar
  765. [2,2], # iterable
  766. np.array(2), # 0-dim
  767. np.r_[2,2], # 1-dim
  768. np.array([[2,0],
  769. [0,2]]), # 2-dim
  770. np.array([[2,0],
  771. [0,2]])[:,:,np.newaxis] # 3-dim
  772. ]
  773. w = wishart(2,np.eye(2))
  774. density = w.pdf(np.array([[2,0],
  775. [0,2]])[:,:,np.newaxis])
  776. for x in X:
  777. assert_equal(w.pdf(x), density)
  778. def test_frozen(self):
  779. # Test that the frozen and non-frozen Wishart gives the same answers
  780. # Construct an arbitrary positive definite scale matrix
  781. dim = 4
  782. scale = np.diag(np.arange(dim)+1)
  783. scale[np.tril_indices(dim, k=-1)] = np.arange(dim * (dim-1) // 2)
  784. scale = np.dot(scale.T, scale)
  785. # Construct a collection of positive definite matrices to test the PDF
  786. X = []
  787. for i in range(5):
  788. x = np.diag(np.arange(dim)+(i+1)**2)
  789. x[np.tril_indices(dim, k=-1)] = np.arange(dim * (dim-1) // 2)
  790. x = np.dot(x.T, x)
  791. X.append(x)
  792. X = np.array(X).T
  793. # Construct a 1D and 2D set of parameters
  794. parameters = [
  795. (10, 1, np.linspace(0.1, 10, 5)), # 1D case
  796. (10, scale, X)
  797. ]
  798. for (df, scale, x) in parameters:
  799. w = wishart(df, scale)
  800. assert_equal(w.var(), wishart.var(df, scale))
  801. assert_equal(w.mean(), wishart.mean(df, scale))
  802. assert_equal(w.mode(), wishart.mode(df, scale))
  803. assert_equal(w.entropy(), wishart.entropy(df, scale))
  804. assert_equal(w.pdf(x), wishart.pdf(x, df, scale))
  805. def test_1D_is_chisquared(self):
  806. # The 1-dimensional Wishart with an identity scale matrix is just a
  807. # chi-squared distribution.
  808. # Test variance, mean, entropy, pdf
  809. # Kolgomorov-Smirnov test for rvs
  810. np.random.seed(482974)
  811. sn = 500
  812. dim = 1
  813. scale = np.eye(dim)
  814. df_range = np.arange(1, 10, 2, dtype=float)
  815. X = np.linspace(0.1,10,num=10)
  816. for df in df_range:
  817. w = wishart(df, scale)
  818. c = chi2(df)
  819. # Statistics
  820. assert_allclose(w.var(), c.var())
  821. assert_allclose(w.mean(), c.mean())
  822. assert_allclose(w.entropy(), c.entropy())
  823. # PDF
  824. assert_allclose(w.pdf(X), c.pdf(X))
  825. # rvs
  826. rvs = w.rvs(size=sn)
  827. args = (df,)
  828. alpha = 0.01
  829. check_distribution_rvs('chi2', args, alpha, rvs)
  830. def test_is_scaled_chisquared(self):
  831. # The 2-dimensional Wishart with an arbitrary scale matrix can be
  832. # transformed to a scaled chi-squared distribution.
  833. # For :math:`S \sim W_p(V,n)` and :math:`\lambda \in \mathbb{R}^p` we have
  834. # :math:`\lambda' S \lambda \sim \lambda' V \lambda \times \chi^2(n)`
  835. np.random.seed(482974)
  836. sn = 500
  837. df = 10
  838. dim = 4
  839. # Construct an arbitrary positive definite matrix
  840. scale = np.diag(np.arange(4)+1)
  841. scale[np.tril_indices(4, k=-1)] = np.arange(6)
  842. scale = np.dot(scale.T, scale)
  843. # Use :math:`\lambda = [1, \dots, 1]'`
  844. lamda = np.ones((dim,1))
  845. sigma_lamda = lamda.T.dot(scale).dot(lamda).squeeze()
  846. w = wishart(df, sigma_lamda)
  847. c = chi2(df, scale=sigma_lamda)
  848. # Statistics
  849. assert_allclose(w.var(), c.var())
  850. assert_allclose(w.mean(), c.mean())
  851. assert_allclose(w.entropy(), c.entropy())
  852. # PDF
  853. X = np.linspace(0.1,10,num=10)
  854. assert_allclose(w.pdf(X), c.pdf(X))
  855. # rvs
  856. rvs = w.rvs(size=sn)
  857. args = (df,0,sigma_lamda)
  858. alpha = 0.01
  859. check_distribution_rvs('chi2', args, alpha, rvs)
  860. class TestMultinomial(object):
  861. def test_logpmf(self):
  862. vals1 = multinomial.logpmf((3,4), 7, (0.3, 0.7))
  863. assert_allclose(vals1, -1.483270127243324, rtol=1e-8)
  864. vals2 = multinomial.logpmf([3, 4], 0, [.3, .7])
  865. assert_allclose(vals2, np.NAN, rtol=1e-8)
  866. vals3 = multinomial.logpmf([3, 4], 0, [-2, 3])
  867. assert_allclose(vals3, np.NAN, rtol=1e-8)
  868. def test_reduces_binomial(self):
  869. # test that the multinomial pmf reduces to the binomial pmf in the 2d
  870. # case
  871. val1 = multinomial.logpmf((3, 4), 7, (0.3, 0.7))
  872. val2 = binom.logpmf(3, 7, 0.3)
  873. assert_allclose(val1, val2, rtol=1e-8)
  874. val1 = multinomial.pmf((6, 8), 14, (0.1, 0.9))
  875. val2 = binom.pmf(6, 14, 0.1)
  876. assert_allclose(val1, val2, rtol=1e-8)
  877. def test_R(self):
  878. # test against the values produced by this R code
  879. # (https://stat.ethz.ch/R-manual/R-devel/library/stats/html/Multinom.html)
  880. # X <- t(as.matrix(expand.grid(0:3, 0:3))); X <- X[, colSums(X) <= 3]
  881. # X <- rbind(X, 3:3 - colSums(X)); dimnames(X) <- list(letters[1:3], NULL)
  882. # X
  883. # apply(X, 2, function(x) dmultinom(x, prob = c(1,2,5)))
  884. n, p = 3, [1./8, 2./8, 5./8]
  885. r_vals = {(0, 0, 3): 0.244140625, (1, 0, 2): 0.146484375,
  886. (2, 0, 1): 0.029296875, (3, 0, 0): 0.001953125,
  887. (0, 1, 2): 0.292968750, (1, 1, 1): 0.117187500,
  888. (2, 1, 0): 0.011718750, (0, 2, 1): 0.117187500,
  889. (1, 2, 0): 0.023437500, (0, 3, 0): 0.015625000}
  890. for x in r_vals:
  891. assert_allclose(multinomial.pmf(x, n, p), r_vals[x], atol=1e-14)
  892. def test_rvs_np(self):
  893. # test that .rvs agrees w/numpy
  894. sc_rvs = multinomial.rvs(3, [1/4.]*3, size=7, random_state=123)
  895. rndm = np.random.RandomState(123)
  896. np_rvs = rndm.multinomial(3, [1/4.]*3, size=7)
  897. assert_equal(sc_rvs, np_rvs)
  898. def test_pmf(self):
  899. vals0 = multinomial.pmf((5,), 5, (1,))
  900. assert_allclose(vals0, 1, rtol=1e-8)
  901. vals1 = multinomial.pmf((3,4), 7, (.3, .7))
  902. assert_allclose(vals1, .22689449999999994, rtol=1e-8)
  903. vals2 = multinomial.pmf([[[3,5],[0,8]], [[-1, 9], [1, 1]]], 8,
  904. (.1, .9))
  905. assert_allclose(vals2, [[.03306744, .43046721], [0, 0]], rtol=1e-8)
  906. x = np.empty((0,2), dtype=np.float64)
  907. vals3 = multinomial.pmf(x, 4, (.3, .7))
  908. assert_equal(vals3, np.empty([], dtype=np.float64))
  909. vals4 = multinomial.pmf([1,2], 4, (.3, .7))
  910. assert_allclose(vals4, 0, rtol=1e-8)
  911. vals5 = multinomial.pmf([3, 3, 0], 6, [2/3.0, 1/3.0, 0])
  912. assert_allclose(vals5, 0.219478737997, rtol=1e-8)
  913. def test_pmf_broadcasting(self):
  914. vals0 = multinomial.pmf([1, 2], 3, [[.1, .9], [.2, .8]])
  915. assert_allclose(vals0, [.243, .384], rtol=1e-8)
  916. vals1 = multinomial.pmf([1, 2], [3, 4], [.1, .9])
  917. assert_allclose(vals1, [.243, 0], rtol=1e-8)
  918. vals2 = multinomial.pmf([[[1, 2], [1, 1]]], 3, [.1, .9])
  919. assert_allclose(vals2, [[.243, 0]], rtol=1e-8)
  920. vals3 = multinomial.pmf([1, 2], [[[3], [4]]], [.1, .9])
  921. assert_allclose(vals3, [[[.243], [0]]], rtol=1e-8)
  922. vals4 = multinomial.pmf([[1, 2], [1,1]], [[[[3]]]], [.1, .9])
  923. assert_allclose(vals4, [[[[.243, 0]]]], rtol=1e-8)
  924. def test_cov(self):
  925. cov1 = multinomial.cov(5, (.2, .3, .5))
  926. cov2 = [[5*.2*.8, -5*.2*.3, -5*.2*.5],
  927. [-5*.3*.2, 5*.3*.7, -5*.3*.5],
  928. [-5*.5*.2, -5*.5*.3, 5*.5*.5]]
  929. assert_allclose(cov1, cov2, rtol=1e-8)
  930. def test_cov_broadcasting(self):
  931. cov1 = multinomial.cov(5, [[.1, .9], [.2, .8]])
  932. cov2 = [[[.45, -.45],[-.45, .45]], [[.8, -.8], [-.8, .8]]]
  933. assert_allclose(cov1, cov2, rtol=1e-8)
  934. cov3 = multinomial.cov([4, 5], [.1, .9])
  935. cov4 = [[[.36, -.36], [-.36, .36]], [[.45, -.45], [-.45, .45]]]
  936. assert_allclose(cov3, cov4, rtol=1e-8)
  937. cov5 = multinomial.cov([4, 5], [[.3, .7], [.4, .6]])
  938. cov6 = [[[4*.3*.7, -4*.3*.7], [-4*.3*.7, 4*.3*.7]],
  939. [[5*.4*.6, -5*.4*.6], [-5*.4*.6, 5*.4*.6]]]
  940. assert_allclose(cov5, cov6, rtol=1e-8)
  941. def test_entropy(self):
  942. # this is equivalent to a binomial distribution with n=2, so the
  943. # entropy .77899774929 is easily computed "by hand"
  944. ent0 = multinomial.entropy(2, [.2, .8])
  945. assert_allclose(ent0, binom.entropy(2, .2), rtol=1e-8)
  946. def test_entropy_broadcasting(self):
  947. ent0 = multinomial.entropy([2, 3], [.2, .3])
  948. assert_allclose(ent0, [binom.entropy(2, .2), binom.entropy(3, .2)],
  949. rtol=1e-8)
  950. ent1 = multinomial.entropy([7, 8], [[.3, .7], [.4, .6]])
  951. assert_allclose(ent1, [binom.entropy(7, .3), binom.entropy(8, .4)],
  952. rtol=1e-8)
  953. ent2 = multinomial.entropy([[7], [8]], [[.3, .7], [.4, .6]])
  954. assert_allclose(ent2,
  955. [[binom.entropy(7, .3), binom.entropy(7, .4)],
  956. [binom.entropy(8, .3), binom.entropy(8, .4)]],
  957. rtol=1e-8)
  958. def test_mean(self):
  959. mean1 = multinomial.mean(5, [.2, .8])
  960. assert_allclose(mean1, [5*.2, 5*.8], rtol=1e-8)
  961. def test_mean_broadcasting(self):
  962. mean1 = multinomial.mean([5, 6], [.2, .8])
  963. assert_allclose(mean1, [[5*.2, 5*.8], [6*.2, 6*.8]], rtol=1e-8)
  964. def test_frozen(self):
  965. # The frozen distribution should agree with the regular one
  966. np.random.seed(1234)
  967. n = 12
  968. pvals = (.1, .2, .3, .4)
  969. x = [[0,0,0,12],[0,0,1,11],[0,1,1,10],[1,1,1,9],[1,1,2,8]]
  970. x = np.asarray(x, dtype=np.float64)
  971. mn_frozen = multinomial(n, pvals)
  972. assert_allclose(mn_frozen.pmf(x), multinomial.pmf(x, n, pvals))
  973. assert_allclose(mn_frozen.logpmf(x), multinomial.logpmf(x, n, pvals))
  974. assert_allclose(mn_frozen.entropy(), multinomial.entropy(n, pvals))
  975. class TestInvwishart(object):
  976. def test_frozen(self):
  977. # Test that the frozen and non-frozen inverse Wishart gives the same
  978. # answers
  979. # Construct an arbitrary positive definite scale matrix
  980. dim = 4
  981. scale = np.diag(np.arange(dim)+1)
  982. scale[np.tril_indices(dim, k=-1)] = np.arange(dim*(dim-1)/2)
  983. scale = np.dot(scale.T, scale)
  984. # Construct a collection of positive definite matrices to test the PDF
  985. X = []
  986. for i in range(5):
  987. x = np.diag(np.arange(dim)+(i+1)**2)
  988. x[np.tril_indices(dim, k=-1)] = np.arange(dim*(dim-1)/2)
  989. x = np.dot(x.T, x)
  990. X.append(x)
  991. X = np.array(X).T
  992. # Construct a 1D and 2D set of parameters
  993. parameters = [
  994. (10, 1, np.linspace(0.1, 10, 5)), # 1D case
  995. (10, scale, X)
  996. ]
  997. for (df, scale, x) in parameters:
  998. iw = invwishart(df, scale)
  999. assert_equal(iw.var(), invwishart.var(df, scale))
  1000. assert_equal(iw.mean(), invwishart.mean(df, scale))
  1001. assert_equal(iw.mode(), invwishart.mode(df, scale))
  1002. assert_allclose(iw.pdf(x), invwishart.pdf(x, df, scale))
  1003. def test_1D_is_invgamma(self):
  1004. # The 1-dimensional inverse Wishart with an identity scale matrix is
  1005. # just an inverse gamma distribution.
  1006. # Test variance, mean, pdf
  1007. # Kolgomorov-Smirnov test for rvs
  1008. np.random.seed(482974)
  1009. sn = 500
  1010. dim = 1
  1011. scale = np.eye(dim)
  1012. df_range = np.arange(5, 20, 2, dtype=float)
  1013. X = np.linspace(0.1,10,num=10)
  1014. for df in df_range:
  1015. iw = invwishart(df, scale)
  1016. ig = invgamma(df/2, scale=1./2)
  1017. # Statistics
  1018. assert_allclose(iw.var(), ig.var())
  1019. assert_allclose(iw.mean(), ig.mean())
  1020. # PDF
  1021. assert_allclose(iw.pdf(X), ig.pdf(X))
  1022. # rvs
  1023. rvs = iw.rvs(size=sn)
  1024. args = (df/2, 0, 1./2)
  1025. alpha = 0.01
  1026. check_distribution_rvs('invgamma', args, alpha, rvs)
  1027. def test_wishart_invwishart_2D_rvs(self):
  1028. dim = 3
  1029. df = 10
  1030. # Construct a simple non-diagonal positive definite matrix
  1031. scale = np.eye(dim)
  1032. scale[0,1] = 0.5
  1033. scale[1,0] = 0.5
  1034. # Construct frozen Wishart and inverse Wishart random variables
  1035. w = wishart(df, scale)
  1036. iw = invwishart(df, scale)
  1037. # Get the generated random variables from a known seed
  1038. np.random.seed(248042)
  1039. w_rvs = wishart.rvs(df, scale)
  1040. np.random.seed(248042)
  1041. frozen_w_rvs = w.rvs()
  1042. np.random.seed(248042)
  1043. iw_rvs = invwishart.rvs(df, scale)
  1044. np.random.seed(248042)
  1045. frozen_iw_rvs = iw.rvs()
  1046. # Manually calculate what it should be, based on the Bartlett (1933)
  1047. # decomposition of a Wishart into D A A' D', where D is the Cholesky
  1048. # factorization of the scale matrix and A is the lower triangular matrix
  1049. # with the square root of chi^2 variates on the diagonal and N(0,1)
  1050. # variates in the lower triangle.
  1051. np.random.seed(248042)
  1052. covariances = np.random.normal(size=3)
  1053. variances = np.r_[
  1054. np.random.chisquare(df),
  1055. np.random.chisquare(df-1),
  1056. np.random.chisquare(df-2),
  1057. ]**0.5
  1058. # Construct the lower-triangular A matrix
  1059. A = np.diag(variances)
  1060. A[np.tril_indices(dim, k=-1)] = covariances
  1061. # Wishart random variate
  1062. D = np.linalg.cholesky(scale)
  1063. DA = D.dot(A)
  1064. manual_w_rvs = np.dot(DA, DA.T)
  1065. # inverse Wishart random variate
  1066. # Supposing that the inverse wishart has scale matrix `scale`, then the
  1067. # random variate is the inverse of a random variate drawn from a Wishart
  1068. # distribution with scale matrix `inv_scale = np.linalg.inv(scale)`
  1069. iD = np.linalg.cholesky(np.linalg.inv(scale))
  1070. iDA = iD.dot(A)
  1071. manual_iw_rvs = np.linalg.inv(np.dot(iDA, iDA.T))
  1072. # Test for equality
  1073. assert_allclose(w_rvs, manual_w_rvs)
  1074. assert_allclose(frozen_w_rvs, manual_w_rvs)
  1075. assert_allclose(iw_rvs, manual_iw_rvs)
  1076. assert_allclose(frozen_iw_rvs, manual_iw_rvs)
  1077. def test_cho_inv_batch(self):
  1078. """Regression test for gh-8844."""
  1079. a0 = np.array([[2, 1, 0, 0.5],
  1080. [1, 2, 0.5, 0.5],
  1081. [0, 0.5, 3, 1],
  1082. [0.5, 0.5, 1, 2]])
  1083. a1 = np.array([[2, -1, 0, 0.5],
  1084. [-1, 2, 0.5, 0.5],
  1085. [0, 0.5, 3, 1],
  1086. [0.5, 0.5, 1, 4]])
  1087. a = np.array([a0, a1])
  1088. ainv = a.copy()
  1089. _cho_inv_batch(ainv)
  1090. ident = np.eye(4)
  1091. assert_allclose(a[0].dot(ainv[0]), ident, atol=1e-15)
  1092. assert_allclose(a[1].dot(ainv[1]), ident, atol=1e-15)
  1093. def test_logpdf_4x4(self):
  1094. """Regression test for gh-8844."""
  1095. X = np.array([[2, 1, 0, 0.5],
  1096. [1, 2, 0.5, 0.5],
  1097. [0, 0.5, 3, 1],
  1098. [0.5, 0.5, 1, 2]])
  1099. Psi = np.array([[9, 7, 3, 1],
  1100. [7, 9, 5, 1],
  1101. [3, 5, 8, 2],
  1102. [1, 1, 2, 9]])
  1103. nu = 6
  1104. prob = invwishart.logpdf(X, nu, Psi)
  1105. # Explicit calculation from the formula on wikipedia.
  1106. p = X.shape[0]
  1107. sig, logdetX = np.linalg.slogdet(X)
  1108. sig, logdetPsi = np.linalg.slogdet(Psi)
  1109. M = np.linalg.solve(X, Psi)
  1110. expected = ((nu/2)*logdetPsi
  1111. - (nu*p/2)*np.log(2)
  1112. - multigammaln(nu/2, p)
  1113. - (nu + p + 1)/2*logdetX
  1114. - 0.5*M.trace())
  1115. assert_allclose(prob, expected)
  1116. class TestSpecialOrthoGroup(object):
  1117. def test_reproducibility(self):
  1118. np.random.seed(514)
  1119. x = special_ortho_group.rvs(3)
  1120. expected = np.array([[-0.99394515, -0.04527879, 0.10011432],
  1121. [0.04821555, -0.99846897, 0.02711042],
  1122. [0.09873351, 0.03177334, 0.99460653]])
  1123. assert_array_almost_equal(x, expected)
  1124. random_state = np.random.RandomState(seed=514)
  1125. x = special_ortho_group.rvs(3, random_state=random_state)
  1126. assert_array_almost_equal(x, expected)
  1127. def test_invalid_dim(self):
  1128. assert_raises(ValueError, special_ortho_group.rvs, None)
  1129. assert_raises(ValueError, special_ortho_group.rvs, (2, 2))
  1130. assert_raises(ValueError, special_ortho_group.rvs, 1)
  1131. assert_raises(ValueError, special_ortho_group.rvs, 2.5)
  1132. def test_frozen_matrix(self):
  1133. dim = 7
  1134. frozen = special_ortho_group(dim)
  1135. rvs1 = frozen.rvs(random_state=1234)
  1136. rvs2 = special_ortho_group.rvs(dim, random_state=1234)
  1137. assert_equal(rvs1, rvs2)
  1138. def test_det_and_ortho(self):
  1139. xs = [special_ortho_group.rvs(dim)
  1140. for dim in range(2,12)
  1141. for i in range(3)]
  1142. # Test that determinants are always +1
  1143. dets = [np.linalg.det(x) for x in xs]
  1144. assert_allclose(dets, [1.]*30, rtol=1e-13)
  1145. # Test that these are orthogonal matrices
  1146. for x in xs:
  1147. assert_array_almost_equal(np.dot(x, x.T),
  1148. np.eye(x.shape[0]))
  1149. def test_haar(self):
  1150. # Test that the distribution is constant under rotation
  1151. # Every column should have the same distribution
  1152. # Additionally, the distribution should be invariant under another rotation
  1153. # Generate samples
  1154. dim = 5
  1155. samples = 1000 # Not too many, or the test takes too long
  1156. ks_prob = .05
  1157. np.random.seed(514)
  1158. xs = special_ortho_group.rvs(dim, size=samples)
  1159. # Dot a few rows (0, 1, 2) with unit vectors (0, 2, 4, 3),
  1160. # effectively picking off entries in the matrices of xs.
  1161. # These projections should all have the same disribution,
  1162. # establishing rotational invariance. We use the two-sided
  1163. # KS test to confirm this.
  1164. # We could instead test that angles between random vectors
  1165. # are uniformly distributed, but the below is sufficient.
  1166. # It is not feasible to consider all pairs, so pick a few.
  1167. els = ((0,0), (0,2), (1,4), (2,3))
  1168. #proj = {(er, ec): [x[er][ec] for x in xs] for er, ec in els}
  1169. proj = dict(((er, ec), sorted([x[er][ec] for x in xs])) for er, ec in els)
  1170. pairs = [(e0, e1) for e0 in els for e1 in els if e0 > e1]
  1171. ks_tests = [ks_2samp(proj[p0], proj[p1])[1] for (p0, p1) in pairs]
  1172. assert_array_less([ks_prob]*len(pairs), ks_tests)
  1173. class TestOrthoGroup(object):
  1174. def test_reproducibility(self):
  1175. np.random.seed(515)
  1176. x = ortho_group.rvs(3)
  1177. x2 = ortho_group.rvs(3, random_state=515)
  1178. # Note this matrix has det -1, distinguishing O(N) from SO(N)
  1179. assert_almost_equal(np.linalg.det(x), -1)
  1180. expected = np.array([[0.94449759, -0.21678569, -0.24683651],
  1181. [-0.13147569, -0.93800245, 0.3207266],
  1182. [0.30106219, 0.27047251, 0.9144431]])
  1183. assert_array_almost_equal(x, expected)
  1184. assert_array_almost_equal(x2, expected)
  1185. def test_invalid_dim(self):
  1186. assert_raises(ValueError, ortho_group.rvs, None)
  1187. assert_raises(ValueError, ortho_group.rvs, (2, 2))
  1188. assert_raises(ValueError, ortho_group.rvs, 1)
  1189. assert_raises(ValueError, ortho_group.rvs, 2.5)
  1190. def test_det_and_ortho(self):
  1191. xs = [[ortho_group.rvs(dim)
  1192. for i in range(10)]
  1193. for dim in range(2,12)]
  1194. # Test that abs determinants are always +1
  1195. dets = np.array([[np.linalg.det(x) for x in xx] for xx in xs])
  1196. assert_allclose(np.fabs(dets), np.ones(dets.shape), rtol=1e-13)
  1197. # Test that we get both positive and negative determinants
  1198. # Check that we have at least one and less than 10 negative dets in a sample of 10. The rest are positive by the previous test.
  1199. # Test each dimension separately
  1200. assert_array_less([0]*10, [np.nonzero(d < 0)[0].shape[0] for d in dets])
  1201. assert_array_less([np.nonzero(d < 0)[0].shape[0] for d in dets], [10]*10)
  1202. # Test that these are orthogonal matrices
  1203. for xx in xs:
  1204. for x in xx:
  1205. assert_array_almost_equal(np.dot(x, x.T),
  1206. np.eye(x.shape[0]))
  1207. def test_haar(self):
  1208. # Test that the distribution is constant under rotation
  1209. # Every column should have the same distribution
  1210. # Additionally, the distribution should be invariant under another rotation
  1211. # Generate samples
  1212. dim = 5
  1213. samples = 1000 # Not too many, or the test takes too long
  1214. ks_prob = .05
  1215. np.random.seed(518) # Note that the test is sensitive to seed too
  1216. xs = ortho_group.rvs(dim, size=samples)
  1217. # Dot a few rows (0, 1, 2) with unit vectors (0, 2, 4, 3),
  1218. # effectively picking off entries in the matrices of xs.
  1219. # These projections should all have the same disribution,
  1220. # establishing rotational invariance. We use the two-sided
  1221. # KS test to confirm this.
  1222. # We could instead test that angles between random vectors
  1223. # are uniformly distributed, but the below is sufficient.
  1224. # It is not feasible to consider all pairs, so pick a few.
  1225. els = ((0,0), (0,2), (1,4), (2,3))
  1226. #proj = {(er, ec): [x[er][ec] for x in xs] for er, ec in els}
  1227. proj = dict(((er, ec), sorted([x[er][ec] for x in xs])) for er, ec in els)
  1228. pairs = [(e0, e1) for e0 in els for e1 in els if e0 > e1]
  1229. ks_tests = [ks_2samp(proj[p0], proj[p1])[1] for (p0, p1) in pairs]
  1230. assert_array_less([ks_prob]*len(pairs), ks_tests)
  1231. @pytest.mark.slow
  1232. def test_pairwise_distances(self):
  1233. # Test that the distribution of pairwise distances is close to correct.
  1234. np.random.seed(514)
  1235. def random_ortho(dim):
  1236. u, _s, v = np.linalg.svd(np.random.normal(size=(dim, dim)))
  1237. return np.dot(u, v)
  1238. for dim in range(2, 6):
  1239. def generate_test_statistics(rvs, N=1000, eps=1e-10):
  1240. stats = np.array([
  1241. np.sum((rvs(dim=dim) - rvs(dim=dim))**2)
  1242. for _ in range(N)
  1243. ])
  1244. # Add a bit of noise to account for numeric accuracy.
  1245. stats += np.random.uniform(-eps, eps, size=stats.shape)
  1246. return stats
  1247. expected = generate_test_statistics(random_ortho)
  1248. actual = generate_test_statistics(scipy.stats.ortho_group.rvs)
  1249. _D, p = scipy.stats.ks_2samp(expected, actual)
  1250. assert_array_less(.05, p)
  1251. class TestRandomCorrelation(object):
  1252. def test_reproducibility(self):
  1253. np.random.seed(514)
  1254. eigs = (.5, .8, 1.2, 1.5)
  1255. x = random_correlation.rvs((.5, .8, 1.2, 1.5))
  1256. x2 = random_correlation.rvs((.5, .8, 1.2, 1.5), random_state=514)
  1257. expected = np.array([[1., -0.20387311, 0.18366501, -0.04953711],
  1258. [-0.20387311, 1., -0.24351129, 0.06703474],
  1259. [0.18366501, -0.24351129, 1., 0.38530195],
  1260. [-0.04953711, 0.06703474, 0.38530195, 1.]])
  1261. assert_array_almost_equal(x, expected)
  1262. assert_array_almost_equal(x2, expected)
  1263. def test_invalid_eigs(self):
  1264. assert_raises(ValueError, random_correlation.rvs, None)
  1265. assert_raises(ValueError, random_correlation.rvs, 'test')
  1266. assert_raises(ValueError, random_correlation.rvs, 2.5)
  1267. assert_raises(ValueError, random_correlation.rvs, [2.5])
  1268. assert_raises(ValueError, random_correlation.rvs, [[1,2],[3,4]])
  1269. assert_raises(ValueError, random_correlation.rvs, [2.5, -.5])
  1270. assert_raises(ValueError, random_correlation.rvs, [1, 2, .1])
  1271. def test_definition(self):
  1272. # Test the definition of a correlation matrix in several dimensions:
  1273. #
  1274. # 1. Det is product of eigenvalues (and positive by construction
  1275. # in examples)
  1276. # 2. 1's on diagonal
  1277. # 3. Matrix is symmetric
  1278. def norm(i, e):
  1279. return i*e/sum(e)
  1280. np.random.seed(123)
  1281. eigs = [norm(i, np.random.uniform(size=i)) for i in range(2, 6)]
  1282. eigs.append([4,0,0,0])
  1283. ones = [[1.]*len(e) for e in eigs]
  1284. xs = [random_correlation.rvs(e) for e in eigs]
  1285. # Test that determinants are products of eigenvalues
  1286. # These are positive by construction
  1287. # Could also test that the eigenvalues themselves are correct,
  1288. # but this seems sufficient.
  1289. dets = [np.fabs(np.linalg.det(x)) for x in xs]
  1290. dets_known = [np.prod(e) for e in eigs]
  1291. assert_allclose(dets, dets_known, rtol=1e-13, atol=1e-13)
  1292. # Test for 1's on the diagonal
  1293. diags = [np.diag(x) for x in xs]
  1294. for a, b in zip(diags, ones):
  1295. assert_allclose(a, b, rtol=1e-13)
  1296. # Correlation matrices are symmetric
  1297. for x in xs:
  1298. assert_allclose(x, x.T, rtol=1e-13)
  1299. def test_to_corr(self):
  1300. # Check some corner cases in to_corr
  1301. # ajj == 1
  1302. m = np.array([[0.1, 0], [0, 1]], dtype=float)
  1303. m = random_correlation._to_corr(m)
  1304. assert_allclose(m, np.array([[1, 0], [0, 0.1]]))
  1305. # Floating point overflow; fails to compute the correct
  1306. # rotation, but should still produce some valid rotation
  1307. # rather than infs/nans
  1308. with np.errstate(over='ignore'):
  1309. g = np.array([[0, 1], [-1, 0]])
  1310. m0 = np.array([[1e300, 0], [0, np.nextafter(1, 0)]], dtype=float)
  1311. m = random_correlation._to_corr(m0.copy())
  1312. assert_allclose(m, g.T.dot(m0).dot(g))
  1313. m0 = np.array([[0.9, 1e300], [1e300, 1.1]], dtype=float)
  1314. m = random_correlation._to_corr(m0.copy())
  1315. assert_allclose(m, g.T.dot(m0).dot(g))
  1316. # Zero discriminant; should set the first diag entry to 1
  1317. m0 = np.array([[2, 1], [1, 2]], dtype=float)
  1318. m = random_correlation._to_corr(m0.copy())
  1319. assert_allclose(m[0,0], 1)
  1320. # Slightly negative discriminant; should be approx correct still
  1321. m0 = np.array([[2 + 1e-7, 1], [1, 2]], dtype=float)
  1322. m = random_correlation._to_corr(m0.copy())
  1323. assert_allclose(m[0,0], 1)
  1324. class TestUnitaryGroup(object):
  1325. def test_reproducibility(self):
  1326. np.random.seed(514)
  1327. x = unitary_group.rvs(3)
  1328. x2 = unitary_group.rvs(3, random_state=514)
  1329. expected = np.array([[0.308771+0.360312j, 0.044021+0.622082j, 0.160327+0.600173j],
  1330. [0.732757+0.297107j, 0.076692-0.4614j, -0.394349+0.022613j],
  1331. [-0.148844+0.357037j, -0.284602-0.557949j, 0.607051+0.299257j]])
  1332. assert_array_almost_equal(x, expected)
  1333. assert_array_almost_equal(x2, expected)
  1334. def test_invalid_dim(self):
  1335. assert_raises(ValueError, unitary_group.rvs, None)
  1336. assert_raises(ValueError, unitary_group.rvs, (2, 2))
  1337. assert_raises(ValueError, unitary_group.rvs, 1)
  1338. assert_raises(ValueError, unitary_group.rvs, 2.5)
  1339. def test_unitarity(self):
  1340. xs = [unitary_group.rvs(dim)
  1341. for dim in range(2,12)
  1342. for i in range(3)]
  1343. # Test that these are unitary matrices
  1344. for x in xs:
  1345. assert_allclose(np.dot(x, x.conj().T), np.eye(x.shape[0]), atol=1e-15)
  1346. def test_haar(self):
  1347. # Test that the eigenvalues, which lie on the unit circle in
  1348. # the complex plane, are uncorrelated.
  1349. # Generate samples
  1350. dim = 5
  1351. samples = 1000 # Not too many, or the test takes too long
  1352. np.random.seed(514) # Note that the test is sensitive to seed too
  1353. xs = unitary_group.rvs(dim, size=samples)
  1354. # The angles "x" of the eigenvalues should be uniformly distributed
  1355. # Overall this seems to be a necessary but weak test of the distribution.
  1356. eigs = np.vstack([scipy.linalg.eigvals(x) for x in xs])
  1357. x = np.arctan2(eigs.imag, eigs.real)
  1358. res = kstest(x.ravel(), uniform(-np.pi, 2*np.pi).cdf)
  1359. assert_(res.pvalue > 0.05)
  1360. def check_pickling(distfn, args):
  1361. # check that a distribution instance pickles and unpickles
  1362. # pay special attention to the random_state property
  1363. # save the random_state (restore later)
  1364. rndm = distfn.random_state
  1365. distfn.random_state = 1234
  1366. distfn.rvs(*args, size=8)
  1367. s = pickle.dumps(distfn)
  1368. r0 = distfn.rvs(*args, size=8)
  1369. unpickled = pickle.loads(s)
  1370. r1 = unpickled.rvs(*args, size=8)
  1371. assert_equal(r0, r1)
  1372. # restore the random_state
  1373. distfn.random_state = rndm
  1374. def test_random_state_property():
  1375. scale = np.eye(3)
  1376. scale[0, 1] = 0.5
  1377. scale[1, 0] = 0.5
  1378. dists = [
  1379. [multivariate_normal, ()],
  1380. [dirichlet, (np.array([1.]), )],
  1381. [wishart, (10, scale)],
  1382. [invwishart, (10, scale)],
  1383. [multinomial, (5, [0.5, 0.4, 0.1])],
  1384. [ortho_group, (2,)],
  1385. [special_ortho_group, (2,)]
  1386. ]
  1387. for distfn, args in dists:
  1388. check_random_state_property(distfn, args)
  1389. check_pickling(distfn, args)