BUG: Fix eigh and cholesky methods of numpy.random.multivariate_normal#15872
BUG: Fix eigh and cholesky methods of numpy.random.multivariate_normal#15872charris merged 1 commit intonumpy:masterfrom
Conversation
|
Needs a test. Would be worth checking why CI is failing too. |
The explanation of the rest of the implementation was convincing.
|
Because the generators may change, the simplest test might be some rough statistics on the result. What do you suggest? |
|
Re the test: We can just use the singular matrix from my example and then check that the first two samples are approx. equal for I do think that we should be consistent about the factor - typically the correlation is done as Note also that if many evals are zero, we could remove these evecs (or columns of U,V for svd) and work with sth like the following: Not sure if it's worth doing this if we re-compute the eigendecomposition/svd every time though. |
There was some discussion of adding the option of passing the left-hand factor, but that actually seems more appropriate to a class based implementation, that is, one could ask for a generator that returned multivariate normals with given covariance. If I needed a bunch of variates, that is how I would do it, but that might not be appropriate for NumPy. |
|
I agree this probably doesn't belong into numpy. I'm surprised scipy's mvn for "frozen" rvs doesn't deal with this, looks like the matrix decomposition is recomputed for each sample here: https://github.com/scipy/scipy/blob/v1.4.1/scipy/stats/_multivariate.py#L660 Torch's MVN does store the factor (though it doesn't allow singular matrices): https://github.com/pytorch/pytorch/blob/master/torch/distributions/multivariate_normal.py#L146-L15 |
Might be worth opening a SciPy issue. |
That is what I was thinking. It shouldn't require too large a sample to get sufficient accuracy to catch big errors like the current one. I would suggest starting with an EDIT: Or even just generating a stream with |
|
52fecae to
796d4a2
Compare
|
Changed to transpose on trailing dims. Added generator-agnostic test for singular covariances. Maybe someone else can take on additional tests checking some basic statistics on the generated samples in a separate PR. |
|
I think the test is too special cased. I think that a rough check the statistics all methods would be useful. For instance, looks like cholesky also yields wrong results. |
|
Oh so the Cholesky samples are broken too. We may as well just go all in on the |
|
We will need a release note to go with this. You can see how to do this by looking at the current release note files in |
3a94a57 to
259e57b
Compare
|
Changed representation internally. Was easiest to use |
259e57b to
0254bb3
Compare
|
Should the tests cover the new |
|
not sure about other rngs, maybe someone who knows the codebase better can clarify? |
There was a problem hiding this comment.
It would be better to use a separate test here, say test_multivariate_normal_stats or some such, that way you can use a new (seeded) rng and and the stats will be independent of possible changes in other parts of the test. This test will fail about 35 times out of a 1000 if the random stream is random. It will also allow marking it as @pytest.mark.slow if we want to do better statistics, currently it is around .6 seconds, which is already a bit slow.
There was a problem hiding this comment.
I mean using a fixed seed and checking the samples will do the trick for validating correctness of the formulation. The statistics test is really more and end-to-end integration test. That should really be done in a "statistical unit testing" setting where you run the test a bunch of times under a hypothesis test and then see that you get reasonably close to your selected significance level across many runs. But that shouldn't be part of the regular test suite.
There was a problem hiding this comment.
But that shouldn't be part of the regular test suite.
I would support adding a validation test suite at some point. But for now we could keep this and move it later. It did uncover the Cholesky problem and would have caught the eigh problem.
The various random functions were tested for statistical accuracy many years ago, we should really have tests somewhere that we could use to revalidate the results since there have been changes since. Hmm, that could almost be a GSOC project next time that rolls around, not that statistical tests are the least bit trivial but the problem is well stated. Validating the generators themselves might be worth something just to make sure we didn't drop the ball somewhere, after all, there was the buggy generation of low precision integers that we should have caught earlier.
numpy/random/_generator.pyx
Outdated
There was a problem hiding this comment.
The problem here is that u is not necessarily vh.T for the svd, if there are negative eigenvalues from numerical error, there will be a sign change. Hmm... if the cov is valid and the negative eigenvalue is due to numerical error, i.e., it is really tiny, then it should have hardly any impact on the output, so this is probably OK. Might mention the possibility in the release note.
There was a problem hiding this comment.
I mean the same is true for the previous formulation, right?
There was a problem hiding this comment.
Yep, it would give incorrect results in that case, but different incorrect results :)
There was a problem hiding this comment.
ok let's make sure our errors are correct then
0254bb3 to
f6e5fe2
Compare
|
Using |
There was a problem hiding this comment.
random = Generator(MT19937(self.seed))
Otherwise it uses the global unseeded generator defined at the top of the file. We should probably get rid of that at some point.
There was a problem hiding this comment.
This could be as tight as before if it works with the seeded generator, it should be repeatable.
f6e5fe2 to
72457f0
Compare
|
Looks good, let's see if the tests pass. |
|
Thanks @Balandat. It is very nice to have those errors fixed and tested. |
|
@charris It would be a good idea. @WarrenWeckesser discovered a casting issue using some Monte Carlo methods IIRC. It would make sense to start with the things that are "newer", e.g., the Ziggurat exponentials, gamma, normals, and the bounded integers. These are all widely used in other distributions. |
Fixes #15871. The
eighandcholeskymethods were not producing results with the correct covariance.