Skip to content

Commit 55c9025

Browse files
authored
Merge pull request #75 from bashtage/update-to-latest-numpy
SYNC: Sync with upstream changes in NumPy
2 parents 4b93e6b + 2fe7652 commit 55c9025

File tree

3 files changed

+46
-21
lines changed

3 files changed

+46
-21
lines changed

randomstate/distributions.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ double random_beta(aug_state *state, double a, double b)
501501
if ((a <= 1.0) && (b <= 1.0))
502502
{
503503
double U, V, X, Y;
504-
/* Use Jonk's algorithm */
504+
/* Use Johnk's algorithm */
505505

506506
while (1)
507507
{

randomstate/randomstate.pyx

+20-7
Original file line numberDiff line numberDiff line change
@@ -3934,9 +3934,10 @@ cdef class RandomState:
39343934
0.0, '', CONS_NONE)
39353935

39363936
# Multivariate distributions:
3937-
def multivariate_normal(self, mean, cov, size=None, method=__normal_method):
3937+
def multivariate_normal(self, mean, cov, size=None, check_valid='warn',
3938+
tol=1e-8, method=__normal_method):
39383939
"""
3939-
multivariate_normal(mean, cov, size=None, method='bm')
3940+
multivariate_normal(mean, cov[, size, check_valid, tol])
39403941
39413942
Draw random samples from a multivariate normal distribution.
39423943
@@ -3959,6 +3960,10 @@ cdef class RandomState:
39593960
generated, and packed in an `m`-by-`n`-by-`k` arrangement. Because
39603961
each sample is `N`-dimensional, the output shape is ``(m,n,k,N)``.
39613962
If no shape is specified, a single (`N`-D) sample is returned.
3963+
check_valid : { 'warn', 'raise', 'ignore' }, optional
3964+
Behavior when the covariance matrix is not positive semidefinite.
3965+
tol : float, optional
3966+
Tolerance when checking the singular values in covariance matrix.
39623967
method : str, optional
39633968
Either 'bm' or 'zig'. 'bm' uses the default Box-Muller transformations
39643969
method. 'zig' uses the much faster Ziggurat method of Marsaglia and Tsang.
@@ -4073,12 +4078,20 @@ cdef class RandomState:
40734078
# not zero. We continue to use the SVD rather than Cholesky in
40744079
# order to preserve current outputs. Note that symmetry has not
40754080
# been checked.
4081+
40764082
(u, s, v) = svd(cov)
4077-
neg = (np.sum(u.T * v, axis=1) < 0) & (s > 0)
4078-
if np.any(neg):
4079-
s[neg] = 0.
4080-
warnings.warn("covariance is not positive-semidefinite.",
4081-
RuntimeWarning)
4083+
4084+
if check_valid != 'ignore':
4085+
if check_valid != 'warn' and check_valid != 'raise':
4086+
raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'")
4087+
4088+
psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol)
4089+
if not psd:
4090+
if check_valid == 'warn':
4091+
warnings.warn("covariance is not positive-semidefinite.",
4092+
RuntimeWarning)
4093+
else:
4094+
raise ValueError("covariance is not positive-semidefinite.")
40824095

40834096
x = np.dot(x, np.sqrt(s)[:, None] * v)
40844097
x += mean

randomstate/tests/tests_numpy_mt19937.py

+25-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import numpy as np
44
from numpy.testing import (
55
TestCase, run_module_suite, assert_, assert_raises, assert_equal,
6-
assert_warns, assert_array_equal, assert_array_almost_equal)
6+
assert_warns, assert_no_warnings, assert_array_equal,
7+
assert_array_almost_equal)
78
from numpy.compat import asbytes
89
import sys
910
import warnings
@@ -614,28 +615,37 @@ def test_multinomial(self):
614615
def test_multivariate_normal(self):
615616
mt19937.seed(self.seed)
616617
mean = (.123456789, 10)
617-
# Hmm... not even symmetric.
618-
cov = [[1, 0], [1, 0]]
618+
cov = [[1, 0], [0, 1]]
619619
size = (3, 2)
620620
actual = mt19937.multivariate_normal(mean, cov, size)
621-
desired = np.array([[[-1.47027513018564449, 10.],
622-
[-1.65915081534845532, 10.]],
623-
[[-2.29186329304599745, 10.],
624-
[-1.77505606019580053, 10.]],
625-
[[-0.54970369430044119, 10.],
626-
[0.29768848031692957, 10.]]])
621+
desired = np.array([[[1.463620246718631, 11.73759122771936 ],
622+
[1.622445133300628, 9.771356667546383]],
623+
[[2.154490787682787, 12.170324946056553],
624+
[1.719909438201865, 9.230548443648306]],
625+
[[0.689515026297799, 9.880729819607714],
626+
[-0.023054015651998, 9.201096623542879]]])
627+
627628
assert_array_almost_equal(actual, desired, decimal=15)
628629

629630
# Check for default size, was raising deprecation warning
630631
actual = mt19937.multivariate_normal(mean, cov)
631-
desired = np.array([-0.79441224511977482, 10.])
632+
desired = np.array([0.895289569463708, 9.17180864067987])
632633
assert_array_almost_equal(actual, desired, decimal=15)
633634

634-
# Check that non positive-semidefinite covariance raises warning
635+
# Check that non positive-semidefinite covariance warns with
636+
# RuntimeWarning
635637
mean = [0, 0]
636-
cov = [[1, 1 + 1e-10], [1 + 1e-10, 1]]
638+
cov = [[1, 2], [2, 1]]
637639
assert_warns(RuntimeWarning, mt19937.multivariate_normal, mean, cov)
638640

641+
# and that it doesn't warn with RuntimeWarning check_valid='ignore'
642+
assert_no_warnings(mt19937.multivariate_normal, mean, cov,
643+
check_valid='ignore')
644+
645+
# and that it raises with RuntimeWarning check_valid='raises'
646+
assert_raises(ValueError, mt19937.multivariate_normal, mean, cov,
647+
check_valid='raise')
648+
639649
def test_negative_binomial(self):
640650
mt19937.seed(self.seed)
641651
actual = mt19937.negative_binomial(n=100, p=.12345, size=(3, 2))
@@ -810,7 +820,9 @@ def test_uniform_range_bounds(self):
810820
assert_raises(OverflowError, func, [0], [np.inf])
811821

812822
# (fmax / 1e17) - fmin is within range, so this should not throw
813-
mt19937.uniform(low=fmin, high=fmax / 1e17)
823+
# account for i386 extended precision DBL_MAX / 1e17 + DBL_MAX >
824+
# DBL_MAX by increasing fmin a bit
825+
mt19937.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17)
814826

815827
def test_vonmises(self):
816828
mt19937.seed(self.seed)

0 commit comments

Comments
 (0)