Skip to content

Commit e230a9f

Browse files
QEDadymeta-codesync[bot]
authored andcommitted
jax-pyrefly-stubs: support DuckTypedArray in *_like and fix logsumexp/truncated_normal stubs (#5633)
Summary: This PR fixes three stub signature mismatches in `jax-pyrefly-stubs`: 1. `jnp.empty_like`, `zeros_like`, `ones_like`, and `full_like` now accept `jax._src.typing.DuckTypedArray` (such as `jax.ShapeDtypeStruct`) in addition to `ArrayLike`, matching `jax/numpy/__init__.pyi`: ```python import jax import jax.numpy as jnp spec = jax.ShapeDtypeStruct((2, 3), jnp.float32) x = jnp.zeros_like(spec) # previously rejected `ShapeDtypeStruct` y = jnp.ones_like(spec, shape=(4, 5)) ``` 2. `jax.nn.initializers.truncated_normal` now uses the runtime parameter names and order `(stddev: float = ..., dtype: Any = ..., lower: float = ..., upper: float = ...)` instead of `(lower, upper, dtype)`: ```python import jax.nn as jnn init = jnn.initializers.truncated_normal(stddev=0.02) # previously failed with `Unexpected keyword argument stddev` ``` 3. `jax.nn.logsumexp` gradual fallback overloads for `return_sign: Literal[False] = False` and `return_sign: Literal[True] = ...` now accept `a: _ArrayLike[Any]` and `axis: Sequence[int] | int | None = None` (matching `logmeanexp`). Previously, non-literal `axis` types or `jax.jit` wrappers fell through to the `return_sign: bool` overload and returned `Array | tuple[Array, Array]` even when `return_sign` was omitted: ```python from collections.abc import Sequence import jax import jax.nn as jnn import jax.numpy as jnp def reduce_lse(x: jax.Array, axis: int | Sequence[int] = -1) -> jax.Array: return jnn.logsumexp(x, axis=axis) # previously inferred `Array | tuple[Array, Array]` x = jnp.ones((3, 4)) out = jax.jit(jnn.logsumexp, static_argnames=("axis",))(x, -1) ``` - [x] I am a human, and I fully understand the code I am submitting. Pull Request resolved: #5633 Test Plan: Added tests and confirmed no test regressions Reviewed By: stroxler Differential Revision: D131505294 fbshipit-source-id: 2ca47516fb4b4c14b308a692b4f42d016f558355
1 parent cc3c377 commit e230a9f

5 files changed

Lines changed: 89 additions & 24 deletions

File tree

‎tensor-shapes/jax-pyrefly-stubs/jax-stubs/nn/__init__.pyi‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,18 @@ def logsumexp[
107107
_Array[reduce_shape(Shape, Axis, KeepDims)],
108108
]: ...
109109
@overload
110-
def logsumexp[
111-
Shape: _Shape = [],
112-
](
113-
a: _ArrayLike[Shape],
114-
axis: Sequence[int] = ...,
110+
def logsumexp(
111+
a: _ArrayLike[Any],
112+
axis: Sequence[int] | int | None = None,
115113
b: _ArrayLike[Any] | None = None,
116114
keepdims: bool = False,
117115
return_sign: Literal[False] = False,
118116
where: Any = None,
119117
) -> _Array[IntTuple]: ...
120118
@overload
121-
def logsumexp[
122-
Shape: _Shape = [],
123-
](
124-
a: _ArrayLike[Shape],
125-
axis: Sequence[int] = ...,
119+
def logsumexp(
120+
a: _ArrayLike[Any],
121+
axis: Sequence[int] | int | None = None,
126122
b: _ArrayLike[Any] | None = None,
127123
keepdims: bool = False,
128124
return_sign: Literal[True] = ...,

‎tensor-shapes/jax-pyrefly-stubs/jax-stubs/nn/initializers.pyi‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ def normal[Shape: _Shape = []](
2222
stddev: float = ..., dtype: Any = ...
2323
) -> Callable[[Any, Shape, Any], _Array[Shape]]: ...
2424
def truncated_normal[Shape: _Shape = []](
25-
lower: float = ..., upper: float = ..., dtype: Any = ...
25+
stddev: float = ...,
26+
dtype: Any = ...,
27+
lower: float = ...,
28+
upper: float = ...,
2629
) -> Callable[[Any, Shape, Any], _Array[Shape]]: ...
2730
def zeros[Shape: _Shape = []](
2831
key: Any, shape: Shape, dtype: Any = ..., out_sharding: Any = ...

‎tensor-shapes/jax-pyrefly-stubs/jax-stubs/numpy/__init__.pyi‎

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ from jax._src.sharding_impls import (
104104
NamedSharding as _NamedSharding,
105105
PartitionSpec as _PartitionSpec,
106106
)
107+
from jax._src.typing import DuckTypedArray as _DuckTypedArray
107108
from jax.sharding import Sharding as _Sharding
108109
from jax.typing import DTypeLike
109110
from numpy import (
@@ -316,24 +317,32 @@ def empty_like[Shape: _Shape = []](
316317
device: _Device | _Sharding | None = ...,
317318
) -> _Array[Shape]: ...
318319
@overload
320+
def empty_like(
321+
prototype: _ArrayLike[Any] | _DuckTypedArray,
322+
dtype: DTypeLike | None = ...,
323+
shape: None = None,
324+
*,
325+
device: _Device | _Sharding | None = ...,
326+
) -> _Array[IntTuple]: ...
327+
@overload
319328
def empty_like[N: IntVar](
320-
prototype: _ArrayLike[Any],
329+
prototype: _ArrayLike[Any] | _DuckTypedArray,
321330
dtype: DTypeLike | None = ...,
322331
shape: Int[N] = ...,
323332
*,
324333
device: _Device | _Sharding | None = ...,
325334
) -> _Array[[N]]: ...
326335
@overload
327336
def empty_like[Shape: _Shape](
328-
prototype: _ArrayLike[Any],
337+
prototype: _ArrayLike[Any] | _DuckTypedArray,
329338
dtype: DTypeLike | None = ...,
330339
shape: Shape = ...,
331340
*,
332341
device: _Device | _Sharding | None = ...,
333342
) -> _Array[Shape]: ...
334343
@overload
335344
def empty_like(
336-
prototype: _ArrayLike[Any],
345+
prototype: _ArrayLike[Any] | _DuckTypedArray,
337346
dtype: DTypeLike | None = ...,
338347
shape: Sequence[int] | int | None = None,
339348
*,
@@ -349,8 +358,17 @@ def zeros_like[Shape: _Shape = []](
349358
out_sharding: _NamedSharding | _PartitionSpec | None = ...,
350359
) -> _Array[Shape]: ...
351360
@overload
361+
def zeros_like(
362+
a: _ArrayLike[Any] | _DuckTypedArray,
363+
dtype: DTypeLike | None = ...,
364+
shape: None = None,
365+
*,
366+
device: _Device | _Sharding | None = ...,
367+
out_sharding: _NamedSharding | _PartitionSpec | None = ...,
368+
) -> _Array[IntTuple]: ...
369+
@overload
352370
def zeros_like[N: IntVar](
353-
a: _ArrayLike[Any],
371+
a: _ArrayLike[Any] | _DuckTypedArray,
354372
dtype: DTypeLike | None = ...,
355373
shape: Int[N] = ...,
356374
*,
@@ -359,7 +377,7 @@ def zeros_like[N: IntVar](
359377
) -> _Array[[N]]: ...
360378
@overload
361379
def zeros_like[Shape: _Shape](
362-
a: _ArrayLike[Any],
380+
a: _ArrayLike[Any] | _DuckTypedArray,
363381
dtype: DTypeLike | None = ...,
364382
shape: Shape = ...,
365383
*,
@@ -368,7 +386,7 @@ def zeros_like[Shape: _Shape](
368386
) -> _Array[Shape]: ...
369387
@overload
370388
def zeros_like(
371-
a: _ArrayLike[Any],
389+
a: _ArrayLike[Any] | _DuckTypedArray,
372390
dtype: DTypeLike | None = ...,
373391
shape: Sequence[int] | int | None = None,
374392
*,
@@ -385,8 +403,17 @@ def ones_like[Shape: _Shape = []](
385403
out_sharding: _NamedSharding | _PartitionSpec | None = ...,
386404
) -> _Array[Shape]: ...
387405
@overload
406+
def ones_like(
407+
a: _ArrayLike[Any] | _DuckTypedArray,
408+
dtype: DTypeLike | None = ...,
409+
shape: None = None,
410+
*,
411+
device: _Device | _Sharding | None = ...,
412+
out_sharding: _NamedSharding | _PartitionSpec | None = ...,
413+
) -> _Array[IntTuple]: ...
414+
@overload
388415
def ones_like[N: IntVar](
389-
a: _ArrayLike[Any],
416+
a: _ArrayLike[Any] | _DuckTypedArray,
390417
dtype: DTypeLike | None = ...,
391418
shape: Int[N] = ...,
392419
*,
@@ -395,7 +422,7 @@ def ones_like[N: IntVar](
395422
) -> _Array[[N]]: ...
396423
@overload
397424
def ones_like[Shape: _Shape](
398-
a: _ArrayLike[Any],
425+
a: _ArrayLike[Any] | _DuckTypedArray,
399426
dtype: DTypeLike | None = ...,
400427
shape: Shape = ...,
401428
*,
@@ -404,7 +431,7 @@ def ones_like[Shape: _Shape](
404431
) -> _Array[Shape]: ...
405432
@overload
406433
def ones_like(
407-
a: _ArrayLike[Any],
434+
a: _ArrayLike[Any] | _DuckTypedArray,
408435
dtype: DTypeLike | None = ...,
409436
shape: Sequence[int] | int | None = None,
410437
*,
@@ -422,8 +449,18 @@ def full_like[Shape: _Shape = []](
422449
out_sharding: _NamedSharding | _PartitionSpec | None = ...,
423450
) -> _Array[Shape]: ...
424451
@overload
452+
def full_like(
453+
a: _ArrayLike[Any] | _DuckTypedArray,
454+
fill_value: Any,
455+
dtype: DTypeLike | None = ...,
456+
shape: None = None,
457+
*,
458+
device: _Device | _Sharding | None = ...,
459+
out_sharding: _NamedSharding | _PartitionSpec | None = ...,
460+
) -> _Array[IntTuple]: ...
461+
@overload
425462
def full_like[N: IntVar](
426-
a: _ArrayLike[Any],
463+
a: _ArrayLike[Any] | _DuckTypedArray,
427464
fill_value: Any,
428465
dtype: DTypeLike | None = ...,
429466
shape: Int[N] = ...,
@@ -433,7 +470,7 @@ def full_like[N: IntVar](
433470
) -> _Array[[N]]: ...
434471
@overload
435472
def full_like[Shape: _Shape](
436-
a: _ArrayLike[Any],
473+
a: _ArrayLike[Any] | _DuckTypedArray,
437474
fill_value: Any,
438475
dtype: DTypeLike | None = ...,
439476
shape: Shape = ...,
@@ -443,7 +480,7 @@ def full_like[Shape: _Shape](
443480
) -> _Array[Shape]: ...
444481
@overload
445482
def full_like(
446-
a: _ArrayLike[Any],
483+
a: _ArrayLike[Any] | _DuckTypedArray,
447484
fill_value: Any,
448485
dtype: DTypeLike | None = ...,
449486
shape: Sequence[int] | int | None = None,

‎tensor-shapes/jax-pyrefly-stubs/test/test_creation.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ def test_like_constructors() -> None:
9595
assert_shape(jnp.full_like(x23, 7.0, shape=(4, 5)).shape, (4, 5))
9696
assert_shape(jnp.full_like(x23, 7.0, shape=(2, 3, 4, 5)).shape, (2, 3, 4, 5))
9797

98+
sds = jax.ShapeDtypeStruct((2, 3), jnp.float32)
99+
assert_shape(jnp.empty_like(sds).shape, IntTuple, runtime=(2, 3))
100+
assert_shape(jnp.empty_like(sds, shape=()).shape, ())
101+
assert_shape(jnp.empty_like(sds, shape=4).shape, (4,))
102+
assert_shape(jnp.empty_like(sds, shape=(4, 5)).shape, (4, 5))
103+
assert_shape(jnp.zeros_like(sds).shape, IntTuple, runtime=(2, 3))
104+
assert_shape(jnp.zeros_like(sds, shape=()).shape, ())
105+
assert_shape(jnp.zeros_like(sds, shape=4).shape, (4,))
106+
assert_shape(jnp.zeros_like(sds, shape=(4, 5)).shape, (4, 5))
107+
assert_shape(jnp.ones_like(sds).shape, IntTuple, runtime=(2, 3))
108+
assert_shape(jnp.ones_like(sds, shape=()).shape, ())
109+
assert_shape(jnp.ones_like(sds, shape=4).shape, (4,))
110+
assert_shape(jnp.ones_like(sds, shape=(4, 5)).shape, (4, 5))
111+
assert_shape(jnp.full_like(sds, 7.0).shape, IntTuple, runtime=(2, 3))
112+
assert_shape(jnp.full_like(sds, 7.0, shape=()).shape, ())
113+
assert_shape(jnp.full_like(sds, 7.0, shape=4).shape, (4,))
114+
assert_shape(jnp.full_like(sds, 7.0, shape=(4, 5)).shape, (4, 5))
115+
98116

99117
def test_non_tuple_shapes_are_gradual() -> None:
100118
# A tuple is exact at any rank. Other sequences remain gradual because only

‎tensor-shapes/jax-pyrefly-stubs/test/test_nn.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import jax
99
import jax.nn as jnn
1010
import jax.numpy as jnp
11-
from shape_extensions import assert_shape, Int, IntVar
11+
from shape_extensions import assert_shape, Int, IntTuple, IntVar
1212

1313
N = IntVar("N")
1414
M = IntVar("M")
@@ -169,6 +169,15 @@ def test_logsumexp_and_logmeanexp() -> None:
169169
assert_shape(res.shape, (4,))
170170
assert_shape(sign.shape, (4,))
171171

172+
dyn_axis: int | list[int] = -1
173+
assert_shape(jnn.logsumexp(x, dyn_axis).shape, IntTuple, runtime=(3,))
174+
dyn_res, dyn_sign = jnn.logsumexp(x, dyn_axis, return_sign=True)
175+
assert_shape(dyn_res.shape, IntTuple, runtime=(3,))
176+
assert_shape(dyn_sign.shape, IntTuple, runtime=(3,))
177+
178+
jitted_lse = jax.jit(jnn.logsumexp, static_argnames=("axis",))(x, -1)
179+
assert_shape((jitted_lse - jnp.sum(x, -1)).shape, IntTuple, runtime=(3,))
180+
172181
assert_shape(jnn.logmeanexp(x).shape, ())
173182
assert_shape(jnn.logmeanexp(x, 0).shape, (4,))
174183
assert_shape(jnn.logmeanexp(x, -1).shape, (3,))
@@ -201,3 +210,5 @@ def test_initializers() -> None:
201210
assert_shape(jnn.initializers.ones(key, (2, 5)).shape, (2, 5))
202211
init = jnn.initializers.normal()
203212
assert_shape(init(key, (4, 4), jnp.float32).shape, (4, 4))
213+
trunc_init = jnn.initializers.truncated_normal(stddev=0.02, lower=-2.0, upper=2.0)
214+
assert_shape(trunc_init(key, (3, 5), jnp.float32).shape, (3, 5))

0 commit comments

Comments
 (0)