Skip to content

rstsr-faer-py (feat): where over rt::where_f, with the i8 x i16 promotion fix - #116

Merged
ajz34 merged 2 commits into
RESTGroup:mainfrom
ajz34:261006/faer-py-where
Oct 6, 2026
Merged

ajz34 merged 2 commits into
RESTGroup:mainfrom
ajz34:261006/faer-py-where

Conversation

@ajz34

@ajz34 ajz34 commented Oct 6, 2026

Copy link
Copy Markdown
Member

Changes

New features

  • rstsr-faer-py exposes the array-API where(condition, x1, x2) — the
    last missing entry of the searching surface (gap G-037): a thin wrapper
    over core rt::where (rt::where_f), with a 169-pair dtype dispatch
    derived from rstsr's promotion matrix, boolean-only conditions, and
    weak-scalar marshalling for Python scalars on either side.

Bug Fix

  • Fix rstsr-dtype-traits' promotion matrix missing DTypePromoteAPI<i16> for i8 (and its DTypeCastAPI twin): the impl line had been swallowed
    by a section comment since 2025-09-29 (ce977a1), so every
    promotion-bound op — maximum/minimum, floor_divide, atan2, copysign,
    hypot, nextafter, logaddexp, comparisons — declined int8 x int16 pairs
    while the mirror row existed. promotion.rs gains an inline test module
    (compile-time completeness over the 13 x 13 matrix, Res checks, and
    value checks for the restored row).

Details

  • The condition must be a bool tensor (the standard's "should have a
    boolean data type"); non-bool conditions are declined, never
    truthiness-cast. A call with two scalars raises, matching the spec's "at
    least one of x1 and x2 must be an array".
  • No promotion table is duplicated in the shim: the new dispatch_where!
    derives the result variant from the promoted type (any_of), like the
    W2 binary dispatch macros.
  • Suites: array-api-tests @ 6c0b59f goes 996 -> 1014 passing, 304 -> 286
    failing, 82 skipped (18 flips / 0 regressions), test-for-test identical
    on a canonical FRESH run and a warm re-run. test_nan_propagation[max]
    and [min] remain red on the registered reduction-NaN gap (rstsr's
    max/min return +/-inf), which is independent of where.

PR summarized by

  • Agent: Claude Code
  • Model: deepseek-v4-flash

ajz34 and others added 2 commits October 6, 2026 18:18
`impl_promotion_asable!(i8, i16, false, true, i16)` had been swallowed by
its section comment since ce977a1 ("Apply type promotion rules",
2025-09-29): the source reads `// internal typeimpl_promotion_asable!(...)`,
so `DTypePromoteAPI<i16> for i8` (and the `DTypeCastAPI<i16> for i8` twin
the same macro emits) never existed, while the mirror row `i16 x i8` did.
Every `DTypePromoteAPI`-bound op (maximum/minimum, floor_divide, atan2,
copysign, hypot, nextafter, logaddexp, comparisons) therefore declined
int8 x int16 pairs; the array-API test suite draws both orderings.

Restored with the flags of the mirror row (`Res = i16`; NumPy's
result_type and the suite's own promotion table agree), and promotion.rs
gains an inline test module: a compile-time completeness check over the
full 13 x 13 matrix of canonical dtypes, `Res` checks for representative
pairs, and value checks for the restored row.

Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: deepseek-v4-flash <service@deepseek.com>
The last missing entry of the searching surface (gap G-037): the shim's
`where` is a thin wrapper over core `rt::where` (rt::where_f), which
landed on main with RESTGroup#114.

- Rust: `op_where` calls `where_f` with the output type taken from
  rstsr's own promotion trait (`TX: DTypePromoteAPI<TY>`); the pyfunction
  is exported as `where` (the Rust keyword forces the `where_` item name;
  the attribute restores it).
- Dispatch: a new `dispatch_where!` — 169 arms, one per dtype pair of the
  13 canonical dtypes. Every arm calls the same generic fn item and the
  result variant follows the promoted type via `any_of`, so the shim
  carries no promotion table of its own (same construction rule as the W2
  binary dispatch macros).
- Python: `where(condition, x1, x2, /)` validates a boolean Array
  condition and marshals x1/x2 through the existing `_operands`
  weak-scalar path (a scalar becomes a 0-d array of the array operand's
  dtype, spec "Mixing arrays with Python scalars"); a call with two
  scalars raises, matching the spec's "at least one of x1 and x2 must be
  an array". Non-boolean conditions are declined, never truthiness-cast.

Suite (array-api-tests @ 6c0b59f): 996 -> 1014 passing, 304 -> 286
failing, 82 skipped — 18 flips / 0 regressions, identical on a canonical
FRESH run and a warm re-run. Besides `test_where` and
`test_where_with_scalars`, this unblocks the suite's own verification
paths that call `xp.where` (getitem, asarray_arrays, eye, tril, triu,
linspace, unstack, positive) and five nan-propagation generators.

Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: deepseek-v4-flash <service@deepseek.com>
@ajz34
ajz34 merged commit 05cf6ce into RESTGroup:main Oct 6, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant