Repository navigation
fix: validate the sampling method and reject an empty mean in multinormal_cholesky - #189
Merged
Merged
Conversation
…rmal_cholesky choose_method returned any value that compared equal to a method id, so np.int64(0), np.int64(2), False and 1.0 passed through unchanged. The callers then compare the result with `is`, so those values were routed to the final else branch (BoxMuller) instead of the method they named. Unrecognized values, such as a misspelled name, were mapped to the default method without any notice. - choose_method now accepts strings from the alias table and integers (including NumPy integers) matching an id, and returns the module-level constant so the `is` comparisons keep working. - bool and float, which compare equal to the ids but are not valid specifications, and any other unrecognized value now emit a UserWarning and fall back to the function's default, like an unrecognized brng does. - multinormal_cholesky raises ValueError for an empty mean instead of ZeroDivisionError. - test_randomdist_lognormal asked lognormal for "Box-Muller2", which it does not support and silently treated as ICDF; it now asserts the warning.
antonwolfy
requested review from
jharlow-intel,
ndgrigorian,
vlad-perevezentsev and
xaleryb
as code owners
October 6, 2026 18:04
…tests Place them next to test_normal_family_array_methods so they do not touch the same lines as other pull requests adding multinormal_cholesky tests.
- choose_method returns a constant passed by identity before any type checks, so the default method no longer pays for isinstance and operator.index on every call. Strings and integers are both resolved through the same loop over mlist. - The warning says the method is "not supported" and lists the methods the called function supports. It looks names up with .get, so a constant missing from _method_names no longer turns the warning into KeyError. - Export ICDF, BOXMULLER, BOXMULLER2, POISNORM and PTPE from mkl_random, as the method docstrings already document them as mkl_random.ICDF etc. - Drop the method entry from the multinomial docstring, which takes no method, and add the missing closing quote in the other ones. - Tests: match the new wording, check the per-function supported list for lognormal and the default named for poisson, and cover the exported ids.
vlad-perevezentsev
approved these changes
Oct 14, 2026
vlad-perevezentsev
left a comment
Collaborator
There was a problem hiding this comment.
No more comments from my side
LGTM
Thank you @antonwolfy
vlad-perevezentsev
self-requested a review
October 15, 2026 12:02
vlad-perevezentsev
approved these changes
Oct 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to the review of #187, which turned up three unrelated behaviours in the Python layer. This PR does not depend on #187 and does not touch the same code.
Problem
choose_methodreturned any value that compared equal to a method id, e.g.np.int64(0),np.int64(2),Falseor1.0. The callers then test the result withis, so those values fell through to the finalelsebranch, which is BoxMuller. For examplemultinormal_cholesky(..., method=np.int64(2))silently ran BoxMuller instead of BoxMuller2, andmethod=Falseran BoxMuller instead of the default.None, or a method the function does not implement (e.g."Box-Muller2"forlognormal, which only supports ICDF and BoxMuller) got the default method without any notice.multinormal_choleskywith an emptymeanraisedZeroDivisionError(PyArray_SIZE(...) // dimwithdim == 0). NumPy'smultivariate_normalraisesValueErrorfor the same input.Changes
choose_method(mkl_random/mklrand.pyx) now accepts strings from the function's alias table and integers (including NumPy integers) matching one of its ids, and returns the module-level constant, so the existingiscomparisons keep working. A constant passed as is, which includes every default argument, is returned before any type checks, so the default path is not slower than on master.bool,floatand any other unsupported value emit aUserWarningthat lists the methods the called function supports, then fall back to that function's default method, in the same style as an unrecognizedbrng. For example:The sampling method 'Box-Muller2' is not supported. Supported methods are "ICDF", "BoxMuller"; "ICDF" will be used instead. Results for those inputs are unchanged apart from the new warning, except where the old code misrouted them (item 1).ICDF,BOXMULLER,BOXMULLER2,POISNORMandPTPEare now exported frommkl_random, since themethoddocstrings already refer to them asmkl_random.ICDFetc. Until now that raisedAttributeError.multinomialdocstring no longer documents amethodparameter, which that function does not take. The othermethoddocstrings get a missing closing quote ('ICDF',).multinormal_choleskyraisesValueError("mean must have at least one element")for an emptymean. oneMKL'svdRngGaussianMValso requiresdimen >= 1.test_randomdist_lognormalaskedlognormalfor"Box-Muller2", which it does not support and silently treated as ICDF. It now asserts the warning, including the supported methods it lists; the expected values are unchanged.CHANGELOG.md: oneAdded, oneChangedand twoFixedentries.Behaviour change to be aware of
Code that passes an unsupported or misspelled
methodstill gets the same numbers as before, but now sees aUserWarning. I chose a warning over an exception to stay backward compatible, consistent with how an unrecognizedbrngis handled (gh-177). RaisingValueErrorinstead would be a small change inchoose_methodif that is preferred.Testing
New tests in
mkl_random/tests/test_random.py:test_multinormal_cholesky_empty_mean: both the 2-D and the packed 1-D empty Cholesky factor raiseValueError.test_multinormal_cholesky_integer_method: for each ofICDF,BoxMuller,BoxMuller2, the ids passed asint,np.int64andnp.uint8give exactly the same draws as the name, and emit no warning.test_unsupported_method_warns_and_uses_default:"bogus",7,-1,1.0,None,False,Trueand[1]warn and give the default (ICDF) result.test_unsupported_method_uses_each_functions_default: the fallback is the called function's own default (poissonfalls back toPOISNORM, not ICDF), and the warning names it as the method used.test_method_tokens_are_exported: each exported id is inmkl_random.__all__, emits no warning, and gives the same draws as its name.Unlike the tests in #187, these fail on master: running them against a master build, 20 of the 25 cases fail (the other 5 are cases master already handled, such as
np.int64(1), which happened to land on BoxMuller). On this branch all 25 pass.The full suite passes (363 passed, 24 skipped), also with
-W error::UserWarning, which confirms that no other call in the test suite triggers the new warning.Timing of calls with the default method (best of 5 interleaved runs, one pinned CPU):
choose_method(ICDF)standard_normal()poisson(3.0)