haliax 1.4.dev318__tar.gz → 1.4.dev321__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 (99) hide show
  1. {haliax-1.4.dev318 → haliax-1.4.dev321}/PKG-INFO +1 -1
  2. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/api.md +2 -1
  3. haliax-1.4.dev321/src/haliax/__about__.py +1 -0
  4. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/einsum.py +14 -2
  5. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/axis.py +22 -4
  6. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/core.py +2 -2
  7. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_axis.py +15 -1
  8. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_einsum.py +6 -3
  9. haliax-1.4.dev318/src/haliax/__about__.py +0 -1
  10. {haliax-1.4.dev318 → haliax-1.4.dev321}/.coveragerc +0 -0
  11. {haliax-1.4.dev318 → haliax-1.4.dev321}/.flake8 +0 -0
  12. {haliax-1.4.dev318 → haliax-1.4.dev321}/.github/workflows/publish_dev.yaml +0 -0
  13. {haliax-1.4.dev318 → haliax-1.4.dev321}/.github/workflows/run_pre_commit.yaml +0 -0
  14. {haliax-1.4.dev318 → haliax-1.4.dev321}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
  15. {haliax-1.4.dev318 → haliax-1.4.dev321}/.github/workflows/run_tests.yaml +0 -0
  16. {haliax-1.4.dev318 → haliax-1.4.dev321}/.gitignore +0 -0
  17. {haliax-1.4.dev318 → haliax-1.4.dev321}/.pre-commit-config.yaml +0 -0
  18. {haliax-1.4.dev318 → haliax-1.4.dev321}/.readthedocs.yaml +0 -0
  19. {haliax-1.4.dev318 → haliax-1.4.dev321}/CONTRIBUTING.md +0 -0
  20. {haliax-1.4.dev318 → haliax-1.4.dev321}/LICENSE +0 -0
  21. {haliax-1.4.dev318 → haliax-1.4.dev321}/README.md +0 -0
  22. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/broadcasting.md +0 -0
  23. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/cheatsheet.md +0 -0
  24. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/css/material.css +0 -0
  25. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/css/mkdocstrings.css +0 -0
  26. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/faq.md +0 -0
  27. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/data_parallel_mesh.png +0 -0
  28. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/data_parallel_mesh_replicated.png +0 -0
  29. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_1d.png +0 -0
  30. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_1d_zero.png +0 -0
  31. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_2d.png +0 -0
  32. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
  33. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
  34. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
  35. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
  36. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/figures/device_mesh_2d_zero.png +0 -0
  37. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/fp8.md +0 -0
  38. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/hof.md +0 -0
  39. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/index.md +0 -0
  40. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/indexing.md +0 -0
  41. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/matmul.md +0 -0
  42. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/nn.md +0 -0
  43. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/partitioning.md +0 -0
  44. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/rearrange.ipynb +0 -0
  45. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/rearrange.md +0 -0
  46. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/requirements.txt +0 -0
  47. {haliax-1.4.dev318 → haliax-1.4.dev321}/docs/tutorial.md +0 -0
  48. {haliax-1.4.dev318 → haliax-1.4.dev321}/mkdocs.yml +0 -0
  49. {haliax-1.4.dev318 → haliax-1.4.dev321}/pyproject.toml +0 -0
  50. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/__init__.py +0 -0
  51. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/__init__.py +0 -0
  52. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/compile_utils.py +0 -0
  53. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/dot.py +0 -0
  54. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/fp8.py +0 -0
  55. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/parsing.py +0 -0
  56. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/rearrange.py +0 -0
  57. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/_src/util.py +0 -0
  58. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/debug.py +0 -0
  59. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/hof.py +0 -0
  60. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/jax_utils.py +0 -0
  61. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/__init__.py +0 -0
  62. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/activations.py +0 -0
  63. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/attention.py +0 -0
  64. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/conv.py +0 -0
  65. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/dropout.py +0 -0
  66. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/embedding.py +0 -0
  67. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/linear.py +0 -0
  68. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/loss.py +0 -0
  69. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/mlp.py +0 -0
  70. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/normalization.py +0 -0
  71. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/pool.py +0 -0
  72. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/nn/scan.py +0 -0
  73. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/ops.py +0 -0
  74. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/partitioning.py +0 -0
  75. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/quantization.py +0 -0
  76. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/random.py +0 -0
  77. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/specialized_fns.py +0 -0
  78. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/tree_util.py +0 -0
  79. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/types.py +0 -0
  80. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/util.py +0 -0
  81. {haliax-1.4.dev318 → haliax-1.4.dev321}/src/haliax/wrap.py +0 -0
  82. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/core_test.py +0 -0
  83. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_attention.py +0 -0
  84. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_conv.py +0 -0
  85. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_debug.py +0 -0
  86. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_dot.py +0 -0
  87. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_fp8.py +0 -0
  88. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_hof.py +0 -0
  89. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_nn.py +0 -0
  90. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_ops.py +0 -0
  91. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_parsing.py +0 -0
  92. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_partitioning.py +0 -0
  93. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_pool.py +0 -0
  94. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_random.py +0 -0
  95. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_rearrange.py +0 -0
  96. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_scan.py +0 -0
  97. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_specialized_fns.py +0 -0
  98. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_tree_util.py +0 -0
  99. {haliax-1.4.dev318 → haliax-1.4.dev321}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: haliax
3
- Version: 1.4.dev318
3
+ Version: 1.4.dev321
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/
@@ -31,10 +31,11 @@ Occasionally, an axis size can be inferred in some circumstances but not others.
31
31
  ::: haliax.axis.axis_name
32
32
  ::: haliax.axis.concat_axes
33
33
  ::: haliax.axis.union_axes
34
+ ::: haliax.axis.intersect_axes
34
35
  ::: haliax.axis.eliminate_axes
35
36
  ::: haliax.axis.without_axes
36
- ::: haliax.axis.overlapping_axes
37
37
  ::: haliax.axis.selects_axis
38
+ ::: haliax.axis.overlapping_axes
38
39
  ::: haliax.axis.is_axis_compatible
39
40
 
40
41
 
@@ -0,0 +1 @@
1
+ __version__ = "1.4.dev321"
@@ -121,10 +121,13 @@ def _output_only_named_einsum(equation, arrays, rhs, axis_aliases):
121
121
  used_aliases = set()
122
122
 
123
123
  input_axis_names = set(ax.name for ax in _all_input_axes(arrays))
124
+ has_ellipsis = False
124
125
 
125
126
  for capture in rhs.captures:
126
127
  if capture is Ellipsis:
127
- raise_parse_error("Can't use ellipsis on the rhs of an einsum without an lhs", equation, None)
128
+ # raise_parse_error("Can't use ellipsis on the rhs of an einsum without an lhs", equation, None)
129
+ out_axes.append(Ellipsis)
130
+ has_ellipsis = True
128
131
  elif capture.binding is None or len(capture.axes) > 1:
129
132
  raise_parse_error(
130
133
  "Parenthesized axes are not currently supported in the output of an einsum",
@@ -150,7 +153,6 @@ def _output_only_named_einsum(equation, arrays, rhs, axis_aliases):
150
153
  )
151
154
 
152
155
  name = ax_name
153
- used_axes.add(name)
154
156
 
155
157
  if name in out_axes:
156
158
  raise_parse_error(
@@ -160,8 +162,18 @@ def _output_only_named_einsum(equation, arrays, rhs, axis_aliases):
160
162
  if name not in input_axis_names:
161
163
  raise_parse_error(f"Axis {name} not found in any of the input arrays", equation, capture.char_range)
162
164
 
165
+ used_axes.add(name)
163
166
  out_axes.append(name)
164
167
 
168
+ # if there's an ellipsis, put all unused axes in the ellipsis
169
+ if has_ellipsis:
170
+ all_input_axes = _all_input_axes(arrays)
171
+ unmentioned = [ax.name for ax in all_input_axes if ax.name not in used_axes]
172
+ ellipsis_index = out_axes.index(Ellipsis)
173
+ out_axes = out_axes[:ellipsis_index] + unmentioned + out_axes[ellipsis_index + 1 :]
174
+
175
+ used_axes = set(out_axes)
176
+
165
177
  _check_for_unused_aliases(axis_aliases, used_aliases, equation)
166
178
 
167
179
  spec = _make_einsum_spec(arrays, out_axes)
@@ -297,21 +297,21 @@ def replace_axis(axis_spec: AxisSelection, old: AxisSelector, new: AxisSelection
297
297
 
298
298
 
299
299
  @overload
300
- def overlapping_axes(ax1: AxisSpec, ax2: AxisSelection) -> Tuple[Axis, ...]:
300
+ def intersect_axes(ax1: AxisSpec, ax2: AxisSelection) -> Tuple[Axis, ...]:
301
301
  ...
302
302
 
303
303
 
304
304
  @overload
305
- def overlapping_axes(ax1: AxisSelection, ax2: AxisSpec) -> Tuple[Axis, ...]:
305
+ def intersect_axes(ax1: AxisSelection, ax2: AxisSpec) -> Tuple[Axis, ...]:
306
306
  ...
307
307
 
308
308
 
309
309
  @overload
310
- def overlapping_axes(ax1: AxisSelection, ax2: AxisSelection) -> Tuple[AxisSelector, ...]:
310
+ def intersect_axes(ax1: AxisSelection, ax2: AxisSelection) -> Tuple[AxisSelector, ...]:
311
311
  ...
312
312
 
313
313
 
314
- def overlapping_axes(ax1: AxisSelection, ax2: AxisSelection) -> Tuple[AxisSelector, ...]:
314
+ def intersect_axes(ax1: AxisSelection, ax2: AxisSelection) -> Tuple[AxisSelector, ...]:
315
315
  """Returns a tuple of axes that are present in both ax1 and ax2.
316
316
  The returned order is the same as ax1.
317
317
  """
@@ -339,6 +339,23 @@ def overlapping_axes(ax1: AxisSelection, ax2: AxisSelection) -> Tuple[AxisSelect
339
339
  return tuple(out)
340
340
 
341
341
 
342
+ def overlapping_axes(ax1: AxisSelection, ax2: AxisSelection) -> Tuple[str, ...]:
343
+ """
344
+ Like intersect_axes, but returns the names instead of the axes themselves.
345
+ Unlike intersect_axes, it does not throw an error if the sizes of a common axis are
346
+ different.
347
+
348
+ The returned order is the same as in ax1.
349
+ """
350
+ ax1 = ensure_tuple(ax1)
351
+ ax2 = ensure_tuple(ax2)
352
+ ax1_names = map(axis_name, ax1)
353
+ ax2_names = set(map(axis_name, ax2))
354
+
355
+ out = tuple(name for name in ax1_names if name in ax2_names)
356
+ return out
357
+
358
+
342
359
  @overload
343
360
  def axis_name(ax: AxisSelector) -> str: # type: ignore
344
361
  ...
@@ -555,6 +572,7 @@ __all__ = [
555
572
  "dslice",
556
573
  "dblock",
557
574
  "eliminate_axes",
575
+ "intersect_axes",
558
576
  "is_axis_compatible",
559
577
  "overlapping_axes",
560
578
  "replace_axis",
@@ -689,9 +689,9 @@ def take(array: NamedArray, axis: AxisSelector, index: Union[int, NamedArray]) -
689
689
  remaining_axes = eliminate_axes(array.axes, axis)
690
690
  # axis order is generally [array.axes[:axis_index], index.axes, array.axes[axis_index + 1 :]]
691
691
  # except that index.axes may overlap with array.axes
692
- overlapping_axes: AxisSpec = haliax.axis.overlapping_axes(remaining_axes, index.axes)
692
+ intersecting_axes: AxisSpec = haliax.axis.intersect_axes(remaining_axes, index.axes)
693
693
 
694
- if overlapping_axes:
694
+ if intersecting_axes:
695
695
  # if the eliminated axis is also in the index, we rename it to a dummy axis that we can broadcast over it
696
696
  need_to_use_dummy_axis = index._lookup_indices(axis.name) is not None
697
697
  if need_to_use_dummy_axis:
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
 
3
- from haliax.axis import Axis, eliminate_axes, make_axes, rearrange_for_partial_order
3
+ from haliax.axis import Axis, eliminate_axes, make_axes, overlapping_axes, rearrange_for_partial_order
4
4
 
5
5
 
6
6
  def test_eliminate_axes():
@@ -133,3 +133,17 @@ def test_duplicate_elements_errors():
133
133
 
134
134
  with pytest.raises(ValueError):
135
135
  rearrange_for_partial_order(partial_order, candidates)
136
+
137
+
138
+ def test_overlapping_axes_with_different_sizes():
139
+ A1 = Axis("A", 10)
140
+ A2 = Axis("A", 12)
141
+ B = Axis("B", 14)
142
+ C = Axis("C", 16)
143
+ D = Axis("D", 18)
144
+
145
+ ax1 = (A1, B, C)
146
+ ax2 = (A2, C, D)
147
+
148
+ overlapping_names = overlapping_axes(ax1, ax2) # Should not error
149
+ assert overlapping_names == ("A", "C")
@@ -250,9 +250,6 @@ def test_einsum_various_errors():
250
250
  m1 = hax.ones((Height, Hidth, Depth))
251
251
  m2 = hax.ones((Depth, Hidth, Height))
252
252
 
253
- with pytest.raises(ValueError, match="Can't use ellipsis"):
254
- einsum("-> ...", m1, m2)
255
-
256
253
  with pytest.raises(ValueError, match="multiple times"):
257
254
  einsum("-> Height Height", m1, m2)
258
255
 
@@ -330,6 +327,12 @@ def test_einsum_output_only_mode():
330
327
  assert jnp.all(jnp.equal(einsum("-> Height Width", m1, m2).array, jnp.einsum("ijk,kji->ij", m1.array, m2.array)))
331
328
  assert jnp.all(jnp.equal(einsum("-> Height", m1).array, jnp.einsum("ijk->i", m1.array)))
332
329
 
330
+ assert jnp.all(jnp.equal(einsum("-> ...", m1, m2).array, jnp.einsum("ijk,kji->ijk", m1.array, m2.array)))
331
+ assert jnp.all(jnp.equal(einsum("-> ... Width", m1, m2).array, jnp.einsum("ijk,kji->ikj", m1.array, m2.array)))
332
+ assert jnp.all(
333
+ jnp.equal(einsum("-> Depth ... Width", m1, m2).array, jnp.einsum("ijk,kji->kij", m1.array, m2.array))
334
+ )
335
+
333
336
  with pytest.raises(ValueError):
334
337
  einsum("-> Q Width", m1)
335
338
 
@@ -1 +0,0 @@
1
- __version__ = "1.4.dev318"
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