Skip to content

fix(view): out= handling, scalar division, and broadcasting in structured views#1146

Merged
henryiii merged 1 commit into
developfrom
fix/view-ufunc-kwargs
Jun 11, 2026
Merged

fix(view): out= handling, scalar division, and broadcasting in structured views#1146
henryiii merged 1 commit into
developfrom
fix/view-ufunc-kwargs

Conversation

@henryiii

Copy link
Copy Markdown
Member

🤖 AI text below 🤖

Part of #1143.

Fixes three verified findings in the structured-view (view.py) ufunc machinery:

B2 — out= silently corrupted reductions

The "reduce" branch of __array_ufunc__ forwarded the caller's out= into _reduce, where np.add.reduce(raw[field], **kwargs) ran once per field with the same out buffer, so each field's reduction overwrote the previous one (e.g. np.sum(v, axis=0, out=np.empty(2)) on a 2-D Weight view returned [(4., 4.), (9., 9.)] instead of [(2., 4.), (3., 9.)]).

Now out= is popped before reducing: if the out dtype matches the view dtype, the result is computed fresh and copied into the out buffer (which is returned); otherwise a TypeError is raised. This applies uniformly to WeightedSumView and the mean views. _MeanArithmetic._reduce now also raises TypeError on reduction arguments it cannot honor (dtype, where, initial) instead of silently ignoring them; axis and keepdims keep working.

B11 — scalar / view produced meaningless statistics

2.0 / weighted_sum_view went through the scalar-first _scale branch and produced variance = s**2 / variance, which is statistically meaningless. The mean views already raise for exactly this case; WeightedSumView now raises a matching TypeError for divide/floor_divide with the view as the divisor. scalar * view and view / scalar are unchanged. (The existing test asserting the old 1 / v behavior was updated to expect the error.)

B12 — legal broadcasts failed

Binary ops preallocated np.empty(self.shape, self.dtype), so a (3,) view plus a (2, 3) array raised ValueError: non-broadcastable output operand. The result is now allocated with np.broadcast_shapes over all inputs; tested in both operand orders for + and *.

Cleanup (from D2)

np.divide is np.true_divide, so the redundant np.true_divide entries in the match alternation and the mean _scale tuple were dropped.

Testing

  • Regression tests added to tests/test_views.py for each finding, including the exact issue reproductions.
  • uv run pytest -n auto --benchmark-disable: 1006 passed, 1 xfailed.
  • mypy (strict) clean; prek -a clean.

🤖 Generated with Claude Code

…ured views

Three fixes in the structured-view ufunc machinery (part of #1143):

- B2: the reduce branch of __array_ufunc__ forwarded the caller's out=
  into the per-field reductions, so every field overwrote the same
  buffer (silently wrong results). out= is now popped before reducing:
  a matching-dtype out is filled from a freshly computed result, and a
  mismatched dtype raises TypeError. _MeanArithmetic._reduce now raises
  on reduction arguments it cannot honor (dtype, where, initial)
  instead of silently ignoring them.

- B11: scalar / WeightedSumView produced a statistically meaningless
  variance (s**2 / variance); it now raises TypeError, matching the
  mean views. scalar * view and view / scalar keep working.

- B12: binary ops preallocated the result with the view's own shape,
  so legal broadcasts (e.g. a (3,) view + a (2, 3) array) failed; the
  result is now allocated with np.broadcast_shapes of all inputs.

Also drops the redundant np.true_divide matches (np.divide is the same
object).

Assisted-by: ClaudeCode:claude-fable-5
@github-actions github-actions Bot added the needs changelog Might need a changelog entry label Jun 11, 2026
@henryiii henryiii marked this pull request as ready for review June 11, 2026 17:30
@henryiii henryiii merged commit 589c2f9 into develop Jun 11, 2026
37 of 39 checks passed
@henryiii henryiii deleted the fix/view-ufunc-kwargs branch June 11, 2026 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs changelog Might need a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant