haliax 1.4.dev396__tar.gz → 1.4.dev398__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. {haliax-1.4.dev396 → haliax-1.4.dev398}/.playbooks/wrap-non-named.md +3 -0
  2. {haliax-1.4.dev396 → haliax-1.4.dev398}/AGENTS.md +2 -1
  3. {haliax-1.4.dev396 → haliax-1.4.dev398}/PKG-INFO +1 -1
  4. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/api.md +1 -0
  5. haliax-1.4.dev398/src/haliax/__about__.py +1 -0
  6. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/__init__.py +2 -0
  7. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/ops.py +28 -0
  8. haliax-1.4.dev398/tests/test_moe_linear.py +70 -0
  9. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_ops.py +16 -0
  10. haliax-1.4.dev396/src/haliax/__about__.py +0 -1
  11. {haliax-1.4.dev396 → haliax-1.4.dev398}/.coveragerc +0 -0
  12. {haliax-1.4.dev396 → haliax-1.4.dev398}/.flake8 +0 -0
  13. {haliax-1.4.dev396 → haliax-1.4.dev398}/.github/workflows/publish_dev.yaml +0 -0
  14. {haliax-1.4.dev396 → haliax-1.4.dev398}/.github/workflows/run_pre_commit.yaml +0 -0
  15. {haliax-1.4.dev396 → haliax-1.4.dev398}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
  16. {haliax-1.4.dev396 → haliax-1.4.dev398}/.github/workflows/run_tests.yaml +0 -0
  17. {haliax-1.4.dev396 → haliax-1.4.dev398}/.gitignore +0 -0
  18. {haliax-1.4.dev396 → haliax-1.4.dev398}/.playbooks/add-types.md +0 -0
  19. {haliax-1.4.dev396 → haliax-1.4.dev398}/.pre-commit-config.yaml +0 -0
  20. {haliax-1.4.dev396 → haliax-1.4.dev398}/.readthedocs.yaml +0 -0
  21. {haliax-1.4.dev396 → haliax-1.4.dev398}/CONTRIBUTING.md +0 -0
  22. {haliax-1.4.dev396 → haliax-1.4.dev398}/LICENSE +0 -0
  23. {haliax-1.4.dev396 → haliax-1.4.dev398}/README.md +0 -0
  24. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/broadcasting.md +0 -0
  25. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/cheatsheet.md +0 -0
  26. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/css/material.css +0 -0
  27. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/css/mkdocstrings.css +0 -0
  28. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/faq.md +0 -0
  29. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/data_parallel_mesh.png +0 -0
  30. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/data_parallel_mesh_replicated.png +0 -0
  31. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_1d.png +0 -0
  32. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_1d_zero.png +0 -0
  33. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_2d.png +0 -0
  34. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
  35. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
  36. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
  37. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
  38. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/figures/device_mesh_2d_zero.png +0 -0
  39. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/fp8.md +0 -0
  40. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/index.md +0 -0
  41. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/indexing.md +0 -0
  42. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/matmul.md +0 -0
  43. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/nn.md +0 -0
  44. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/partitioning.md +0 -0
  45. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/primer.md +0 -0
  46. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/rearrange.ipynb +0 -0
  47. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/rearrange.md +0 -0
  48. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/requirements.txt +0 -0
  49. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/scan.md +0 -0
  50. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/state-dict.md +0 -0
  51. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/tutorial.md +0 -0
  52. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/typing.md +0 -0
  53. {haliax-1.4.dev396 → haliax-1.4.dev398}/docs/vmap.md +0 -0
  54. {haliax-1.4.dev396 → haliax-1.4.dev398}/mkdocs.yml +0 -0
  55. {haliax-1.4.dev396 → haliax-1.4.dev398}/pyproject.toml +0 -0
  56. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/__init__.py +0 -0
  57. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/compile_utils.py +0 -0
  58. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/dot.py +0 -0
  59. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/einsum.py +0 -0
  60. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/fp8.py +0 -0
  61. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/parsing.py +0 -0
  62. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/rearrange.py +0 -0
  63. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/scan.py +0 -0
  64. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/state_dict.py +0 -0
  65. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/_src/util.py +0 -0
  66. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/axis.py +0 -0
  67. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/core.py +0 -0
  68. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/debug.py +0 -0
  69. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/haxtyping.py +0 -0
  70. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/hof.py +0 -0
  71. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/jax_utils.py +0 -0
  72. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/__init__.py +0 -0
  73. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/activations.py +0 -0
  74. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/attention.py +0 -0
  75. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/conv.py +0 -0
  76. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/dropout.py +0 -0
  77. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/embedding.py +0 -0
  78. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/linear.py +0 -0
  79. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/loss.py +0 -0
  80. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/mlp.py +0 -0
  81. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/normalization.py +0 -0
  82. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/pool.py +0 -0
  83. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/nn/scan.py +0 -0
  84. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/partitioning.py +0 -0
  85. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/quantization.py +0 -0
  86. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/random.py +0 -0
  87. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/specialized_fns.py +0 -0
  88. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/state_dict.py +0 -0
  89. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/tree_util.py +0 -0
  90. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/types.py +0 -0
  91. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/util.py +0 -0
  92. {haliax-1.4.dev396 → haliax-1.4.dev398}/src/haliax/wrap.py +0 -0
  93. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/core_test.py +0 -0
  94. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_attention.py +0 -0
  95. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_axis.py +0 -0
  96. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_conv.py +0 -0
  97. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_debug.py +0 -0
  98. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_dot.py +0 -0
  99. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_dtype_typing.py +0 -0
  100. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_einsum.py +0 -0
  101. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_fp8.py +0 -0
  102. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_hof.py +0 -0
  103. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_int8.py +0 -0
  104. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_namedarray_typing.py +0 -0
  105. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_nn.py +0 -0
  106. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_parsing.py +0 -0
  107. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_partitioning.py +0 -0
  108. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_pool.py +0 -0
  109. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_random.py +0 -0
  110. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_rearrange.py +0 -0
  111. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_scan.py +0 -0
  112. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_scatter_gather.py +0 -0
  113. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_specialized_fns.py +0 -0
  114. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_state_dict.py +0 -0
  115. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_tree_util.py +0 -0
  116. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_utils.py +0 -0
  117. {haliax-1.4.dev396 → haliax-1.4.dev398}/tests/test_visualize_sharding.py +0 -0
  118. {haliax-1.4.dev396 → haliax-1.4.dev398}/uv.lock +0 -0
@@ -47,3 +47,6 @@ Some functions need bespoke handling. For example `jnp.unique` returns several a
47
47
 
48
48
  ## Testing
49
49
  Add tests to ensure that named and unnamed calls produce the same results and that axis names are preserved or removed correctly.
50
+
51
+ ## Documentation
52
+ Once your wrapper works, document it. Add `::: haliax.your_function` (replacing the name) to `docs/api.md` so users can find the new API.
@@ -41,7 +41,8 @@ repository. Follow these notes when implementing new features or fixing bugs.
41
41
  `[Object 1][full.path.object1]`)
42
42
  * **Documentation**: When adding new features, ensure that the documentation is updated accordingly.
43
43
  This includes updating the Mkdocs files and any relevant docstrings. If you add a new module or
44
- significant functionality, consider adding a dedicated section in the documentation.
44
+ significant functionality, consider adding a dedicated section in the documentation. When you
45
+ wrap a new JAX function, add a reference to it in `docs/api.md` so users can discover it.
45
46
 
46
47
  ## Testing
47
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haliax
3
- Version: 1.4.dev396
3
+ Version: 1.4.dev398
4
4
  Summary: Named Tensors for Legible Deep Learning in JAX
5
5
  Project-URL: Homepage, https://github.com/stanford-crfm/haliax
6
6
  Project-URL: Bug Tracker, https://github.com/stanford-crfm/haliax/issues/
@@ -256,6 +256,7 @@ These are all more or less directly from JAX's NumPy API.
256
256
 
257
257
  ### Other Operations
258
258
 
259
+ ::: haliax.bincount
259
260
  ::: haliax.clip
260
261
  ::: haliax.isclose
261
262
  ::: haliax.pad
@@ -0,0 +1 @@
1
+ __version__ = "1.4.dev398"
@@ -79,6 +79,7 @@ from .ops import (
79
79
  unique_counts,
80
80
  unique_inverse,
81
81
  unique_all,
82
+ bincount,
82
83
  where,
83
84
  )
84
85
  from .partitioning import auto_sharded, axis_mapping, fsdp, named_jit, shard, shard_with_axis_mapping
@@ -1053,6 +1054,7 @@ __all__ = [
1053
1054
  "unique_counts",
1054
1055
  "unique_inverse",
1055
1056
  "unique_all",
1057
+ "bincount",
1056
1058
  "clip",
1057
1059
  "tril",
1058
1060
  "triu",
@@ -430,6 +430,33 @@ def unique_all(
430
430
  return values, indices, inverse, counts
431
431
 
432
432
 
433
+ def bincount(
434
+ x: NamedArray,
435
+ Counts: Axis,
436
+ *,
437
+ weights: NamedArray | ArrayLike | None = None,
438
+ minlength: int = 0,
439
+ ) -> NamedArray:
440
+ """Named version of `jax.numpy.bincount`.
441
+
442
+ The output axis is specified by ``Counts``.
443
+ """
444
+
445
+ if x.ndim != 1:
446
+ raise ValueError("bincount only supports 1D arrays")
447
+
448
+ w_array = None
449
+ if weights is not None:
450
+ if isinstance(weights, NamedArray):
451
+ weights = haliax.broadcast_to(weights, x.axes)
452
+ w_array = weights.array
453
+ else:
454
+ w_array = jnp.asarray(weights)
455
+
456
+ result = jnp.bincount(x.array, weights=w_array, minlength=minlength, length=Counts.size)
457
+ return NamedArray(result, (Counts,))
458
+
459
+
433
460
  __all__ = [
434
461
  "trace",
435
462
  "where",
@@ -444,4 +471,5 @@ __all__ = [
444
471
  "unique_counts",
445
472
  "unique_inverse",
446
473
  "unique_all",
474
+ "bincount",
447
475
  ]
@@ -0,0 +1,70 @@
1
+ import jax
2
+ import jax.random as jrandom
3
+ from jax import numpy as jnp
4
+
5
+ import haliax as hax
6
+ from haliax.nn import MoELinear
7
+
8
+
9
+ def _expected_moe_linear_output(moe: MoELinear, x: hax.NamedArray, group_sizes: hax.NamedArray):
10
+ dim_numbers = jax.lax.RaggedDotDimensionNumbers(
11
+ (
12
+ ((x.axis_indices(moe.In),), (moe.weight.axis_indices(moe.In),)),
13
+ ((), ()),
14
+ ),
15
+ x.axis_indices(hax.axis.without_axes(x.axes, moe.In)),
16
+ (moe.weight.axis_indices(moe.Experts),),
17
+ )
18
+ out_raw = jax.lax.ragged_dot_general(
19
+ lhs=x.array,
20
+ rhs=moe.weight.array,
21
+ group_sizes=group_sizes.array,
22
+ ragged_dot_dimension_numbers=dim_numbers,
23
+ )
24
+ out_axes = hax.replace_axis(x.axes, moe.In, moe.Out)
25
+ out = hax.named(out_raw, out_axes)
26
+ if moe.bias is not None:
27
+ out = out + moe.bias
28
+ return out
29
+
30
+
31
+ def test_moe_linear_matches_ragged_dot_general():
32
+ B, In, Out, E = hax.make_axes(B=3, In=4, Out=5, E=2)
33
+ key = jrandom.PRNGKey(0)
34
+ moe = MoELinear.init(E, In, Out, key=key)
35
+
36
+ x = hax.random.normal(jrandom.PRNGKey(1), (B, In))
37
+ group_sizes = hax.named(jnp.array([2, 1], dtype=jnp.int32), (E,))
38
+
39
+ actual = moe(x, group_sizes)
40
+ expected = _expected_moe_linear_output(moe, x, group_sizes)
41
+
42
+ assert actual.axes == expected.axes
43
+ assert jnp.allclose(actual.array, expected.array, rtol=1e-5, atol=1e-5)
44
+
45
+
46
+ def test_moe_linear_out_first_property():
47
+ E, In, Out = hax.make_axes(E=2, In=4, Out=3)
48
+ moe = MoELinear.init(E, In, Out, key=jrandom.PRNGKey(0), out_first=True)
49
+ assert moe.out_first
50
+ assert moe.weight.axes[:3] == (E, Out, In)
51
+
52
+ moe2 = MoELinear.init(E, In, Out, key=jrandom.PRNGKey(1), out_first=False)
53
+ assert not moe2.out_first
54
+ assert moe2.weight.axes[:3] == (E, In, Out)
55
+
56
+
57
+ def test_moe_linear_gmm_matches_ragged_dot_general():
58
+ B, In, Out, E = hax.make_axes(B=3, In=4, Out=5, E=2)
59
+ moe = MoELinear.init(E, In, Out, key=jrandom.PRNGKey(0), use_gmm=True)
60
+
61
+ x = hax.random.normal(jrandom.PRNGKey(1), (B, In))
62
+ group_sizes = hax.named(jnp.array([2, 1], dtype=jnp.int32), (E,))
63
+
64
+ with jax.sharding.Mesh(jax.devices(), ("data",)):
65
+ actual = moe(x, group_sizes)
66
+
67
+ expected = _expected_moe_linear_output(moe, x, group_sizes)
68
+
69
+ assert actual.axes == expected.axes
70
+ assert jnp.allclose(actual.array, expected.array, rtol=1e-5, atol=1e-5)
@@ -407,3 +407,19 @@ def test_unique_shortcuts():
407
407
  assert jnp.all(ia.array == ia_exp.array)
408
408
  assert jnp.all(ina.array == ina_exp.array)
409
409
  assert jnp.all(ca.array == ca_exp.array)
410
+
411
+
412
+ def test_bincount():
413
+ X = Axis("X", 6)
414
+ x = hax.named([0, 1, 1, 2, 3, 1], (X,))
415
+ B = Axis("B", 5)
416
+
417
+ out = hax.bincount(x, B)
418
+ expected = jnp.bincount(x.array, length=B.size)
419
+ assert out.axes == (B,)
420
+ assert jnp.all(out.array == expected)
421
+
422
+ w = hax.arange((X,), dtype=jnp.float32)
423
+ out_w = hax.bincount(x, B, weights=w)
424
+ expected_w = jnp.bincount(x.array, weights=w.array, length=B.size)
425
+ assert jnp.allclose(out_w.array, expected_w)
@@ -1 +0,0 @@
1
- __version__ = "1.4.dev396"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes