Skip to content

FIX: align draw's Python size dispatch with the jitted path (#918) - #955

Merged
mmcky merged 2 commits into
mainfrom
fix/draw-numpy-integer-size-918
Oct 8, 2026
Merged

mmcky merged 2 commits into
mainfrom
fix/draw-numpy-integer-size-918

Conversation

@mmcky

@mmcky mmcky commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

Aligns the Python size dispatch in quantecon.random.draw with the jitted path. Replaces #919, which was closed with thanks; this is the reduced form of the same fix.

The bug

draw decides between "an array of size draws" and "one scalar draw" in two places, with two tests that do not agree:

Path Test
Pure Python body isinstance(size, int)
@overload implementation isinstance(size, types.Integer)

A NumPy integer is not a Python int but is a types.Integer, so the same call returns different things depending on whether the call site is jit-compiled — and nothing warns. This is easy to hit: size arrives as np.int64 from any ordinary numpy expression (counts[i], arr.sum(), arr.argmax(), a // on an array), while len(x) and arr.shape[0] give Python ints and are fine, which is why it survives casual testing.

The change

One line in the Python body:

if isinstance(size, (int, np.integer)):

A bool size is not a supported input and is out of scope: NumPy rejects random(True) on the Python path, as it does today, and the jitted path is unchanged.

The @overload needs no change. types.Boolean is not a subclass of types.Integer, so the jitted path already dispatches every case correctly — only the Python body was wrong.

Verified

Dispatch table on this branch, Python against jitted, for every case in #918:

size Python Jitted
10 array(10,) array(10,) agree
np.int64(10) array(10,) array(10,) agree
np.int32(10) array(10,) array(10,) agree
np.uint8(10) array(10,) array(10,) agree
10.0 scalar scalar agree
None scalar scalar agree

None was checked across all four call shapes — omitted and explicit, from Python and from a jitted caller — since _is_no_rng shows Numba spells "no value" more than one way.

  • Full suite: 679 passed
  • flake8 --select=F401,F405,E231 quantecon: clean
  • git diff --check: clean

Release note needed

draw(cdf, np.int64(10)) now returns ten draws from Python where it previously returned one scalar. That is what the caller asked for, and what jitted callers already received, but it is a silent behaviour change and should be called out in the next release's notes. Per AGENTS.md there is no per-PR changelog entry to add.

Closes #918. Replaces #919.

🤖 Generated with Claude Code

`quantecon.random.draw` chose between an array of draws and a single
scalar draw with `isinstance(size, int)` in the Python body and
`isinstance(size, types.Integer)` in the `@overload`. A NumPy integer is
not a Python `int` but is a `types.Integer`, so `draw(cdf, np.int64(10))`
returned one scalar from Python and ten draws from a jitted caller, with
no error either way. `bool` is the reverse case: it passes
`isinstance(x, int)` but Numba types it as `Boolean`.

Widening the Python predicate to `(int, np.integer)` and excluding `bool`
makes the two paths agree on every input in #918's table, verified
including `None` across all four call shapes.

The `@overload` needs no change: `types.Boolean` is not a subclass of
`types.Integer`, so the jitted path already dispatches every case
correctly.

Behaviour change: `draw(cdf, np.int64(10))` now returns ten draws from
Python where it previously returned one scalar. That is what the caller
asked for and what jitted callers already received, but it is silent and
needs a line in the 0.12.0 release notes.

Closes #918. Replaces #919.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 9, 2026 06:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A regression test for the size=True / np.bool_(True) scalar-dispatch case is still missing even though the change explicitly addresses that edge case.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes an inconsistency in quantecon.random.draw where the pure-Python implementation treated size=np.int64(10) as a scalar draw, while the Numba-jitted overload treated it as an array-sized draw, leading to divergent return types depending on whether the caller was jit-compiled.

Changes:

  • Update the pure-Python draw size-dispatch predicate to accept NumPy integer scalars (and explicitly exclude bool) so it matches the @overload dispatch behavior.
  • Add a regression test asserting NumPy-integer size requests an array return for both Python and jitted call paths.
File summaries
File Description
quantecon/random/utilities.py Align pure-Python size dispatch with the Numba overload by accepting np.integer (excluding bool).
quantecon/random/tests/test_utilities.py Add regression coverage ensuring NumPy integer size returns an array on both call paths.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread quantecon/random/tests/test_utilities.py
@coveralls

coveralls commented Sep 9, 2026 •

Copy link
Copy Markdown

Coverage Status

coverage: 94.088% (+3.2%) from 90.884% — fix/draw-numpy-integer-size-918 into main

@oyamad oyamad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's my thought: I wouldn't make (the Python version of) draw(cdf, size=True) return any value. As I stated in #917 (comment), we should only fix the bug I had introduced, keeping the behavior of the Python version "unspecified" or "unsupported" (the @overload is the contract). And thus I wouldn't add any new test.

Comment thread quantecon/random/utilities.py Outdated
Per review, `isinstance(size, (int, np.integer))` is enough: a bool size
is not a supported input, and NumPy rejects it on the Python path as it
does today.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@mmcky mmcky added the bug label Oct 8, 2026
@mmcky
mmcky merged commit 7328de3 into main Oct 8, 2026
15 checks passed
@mmcky
mmcky deleted the fix/draw-numpy-integer-size-918 branch October 8, 2026 00:28
@mmcky mmcky mentioned this pull request Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

random.draw: size dispatch diverges between the Python and jitted paths for numpy integers

4 participants