haliax 1.4.dev411__tar.gz → 1.4.dev413__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.
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.agents/projects/api_parity.md +13 -18
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.playbooks/wrap-non-named.md +8 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/PKG-INFO +1 -1
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/api.md +124 -11
- haliax-1.4.dev413/docs/primer.md +183 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/__about__.py +1 -1
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/__init__.py +22 -0
- haliax-1.4.dev413/src/haliax/fft.py +365 -0
- haliax-1.4.dev413/tests/test_fft.py +81 -0
- haliax-1.4.dev411/docs/primer.md +0 -114
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.coveragerc +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.flake8 +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.gitignore +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.playbooks/add-types.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/AGENTS.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/AUTHORS.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/CONTRIBUTORS.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/LICENSE +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/README.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/css/material.css +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/faq.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/fp8.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/index.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/indexing.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/matmul.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/nn.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/partitioning.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/rearrange.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/requirements.txt +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/scan.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/state-dict.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/tutorial.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/typing.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/docs/vmap.md +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/etc/license_header.txt +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/mkdocs.yml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/pyproject.toml +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/state_dict.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/core.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/field.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/haxtyping.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/__init__.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/linear.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/nn/scan.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/partitioning.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/random.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/types.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/util.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/core_test.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_attention.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_axis.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_bitwise_ops.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_conv.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_debug.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_dot.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_dtype_typing.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_field.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_hof.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_int8.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_moe_linear.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_namedarray_typing.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_nan_reductions.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_nn.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_ops.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_partitioning.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_pool.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_random.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_scan.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_scatter_gather.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_state_dict.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_tree_util.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_utils.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/tests/test_visualize_sharding.py +0 -0
- {haliax-1.4.dev411 → haliax-1.4.dev413}/uv.lock +0 -0
|
@@ -161,24 +161,19 @@ APIs that don't translate well to named tensors are intentionally omitted here.
|
|
|
161
161
|
- [ ] `vstack`
|
|
162
162
|
|
|
163
163
|
## fft
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
- [
|
|
168
|
-
- [
|
|
169
|
-
- [
|
|
170
|
-
- [
|
|
171
|
-
- [
|
|
172
|
-
- [
|
|
173
|
-
- [
|
|
174
|
-
- [
|
|
175
|
-
- [
|
|
176
|
-
- [
|
|
177
|
-
- [ ] `irfftn`
|
|
178
|
-
- [ ] `rfft`
|
|
179
|
-
- [ ] `rfft2`
|
|
180
|
-
- [ ] `rfftfreq`
|
|
181
|
-
- [ ] `rfftn`
|
|
164
|
+
Multi-dimensional transforms like `fftn` or `rfft2` are handled by passing a
|
|
165
|
+
mapping of axes to :func:`haliax.fft` and friends.
|
|
166
|
+
|
|
167
|
+
- [x] `fft`
|
|
168
|
+
- [x] `fftfreq`
|
|
169
|
+
- [x] `fftshift`
|
|
170
|
+
- [x] `hfft`
|
|
171
|
+
- [x] `ifft`
|
|
172
|
+
- [x] `ifftshift`
|
|
173
|
+
- [x] `ihfft`
|
|
174
|
+
- [x] `irfft`
|
|
175
|
+
- [x] `rfft`
|
|
176
|
+
- [x] `rfftfreq`
|
|
182
177
|
|
|
183
178
|
## linalg
|
|
184
179
|
- [ ] `cholesky`
|
|
@@ -45,6 +45,14 @@ def sum(a, axis=None):
|
|
|
45
45
|
## Harder Cases
|
|
46
46
|
Some functions need bespoke handling. For example `jnp.unique` returns several arrays and may change shape unpredictably. There is no generic helper, so you will need to manually map between `NamedArray` axes and the outputs. Use the lower level utilities in `haliax.wrap` for broadcasting and axis lookup.
|
|
47
47
|
|
|
48
|
+
## Axis-aware functions
|
|
49
|
+
For JAX functions that accept an ``axis`` or ``axes`` argument, prefer a single
|
|
50
|
+
``axis`` parameter of type :class:`haliax.AxisSelection` that also accepts an
|
|
51
|
+
ordered mapping of axes to sizes. A mapping dispatches to the corresponding
|
|
52
|
+
``n``‑dimensional JAX primitive (e.g. :func:`jax.numpy.fft.fftn`) and allows
|
|
53
|
+
resizing the transformed axes by specifying integer lengths or ``Axis``
|
|
54
|
+
instances.
|
|
55
|
+
|
|
48
56
|
## Testing
|
|
49
57
|
Add tests to ensure that named and unnamed calls produce the same results and that axis names are preserved or removed correctly.
|
|
50
58
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev413
|
|
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/
|
|
@@ -6,19 +6,89 @@ arrays (see [haliax.zeros][] and [haliax.ones][]) as well as things like reducti
|
|
|
6
6
|
|
|
7
7
|
## Axis Types
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
If you already speak NumPy or `jax.numpy`, think of Haliax as swapping positional axes (`axis=0`) for named axes
|
|
10
|
+
(`axis="batch"`). The type hints in this section describe the different ways those named axes can be provided to the API.
|
|
11
|
+
They appear throughout the documentation and in signatures so that you can quickly tell which forms are accepted.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
This type is used when we want one or more axes and the sizes can be inferred from the inputs, for instance when
|
|
18
|
-
reducing an array.
|
|
13
|
+
| Name | Accepts | When to use it | Example |
|
|
14
|
+
| --- | --- | --- | --- |
|
|
15
|
+
| [`Axis`][haliax.Axis] | `Axis(name: str, size: int)` | Define a named dimension with an explicit size | `Batch = Axis("batch", 32)` |
|
|
16
|
+
| [`AxisSelector`][haliax.AxisSelector] | `Axis` or `str` | Refer to an existing axis whose size can be inferred from the arrays you pass in | `x.sum(axis="batch")` |
|
|
17
|
+
| [`AxisSpec`][haliax.AxisSpec] | `dict[str, int]`, `Axis`, or a sequence of `Axis` objects | Create or reshape arrays when the axis sizes must be provided | `hax.zeros((Batch, Feature))` |
|
|
18
|
+
| [`AxisSelection`][haliax.AxisSelection] | `dict[str, int | None]`, `AxisSpec`, or a sequence of `AxisSelector` values | Work with one or more existing axes (reductions, indexing helpers, flattening, …) | `x.sum(axis=("batch", Feature))` |
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
### Axis
|
|
21
|
+
|
|
22
|
+
An [`Axis`][haliax.Axis] is the fundamental building block: it is a tiny dataclass that stores a name and a size. You can
|
|
23
|
+
construct one directly or use [`haliax.make_axes`][] to generate several at a time.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import haliax as hax
|
|
27
|
+
from haliax import Axis
|
|
28
|
+
|
|
29
|
+
Batch = Axis("batch", 32)
|
|
30
|
+
Feature = Axis("feature", 128)
|
|
31
|
+
x = hax.ones((Batch, Feature))
|
|
32
|
+
print(Batch.name, Batch.size)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Using `Axis` objects keeps array creation explicit and gives reusable handles you can share between different tensors.
|
|
36
|
+
Equality compares both the name and size so you get guardrails when wiring pieces together.
|
|
37
|
+
|
|
38
|
+
### AxisSelector
|
|
39
|
+
|
|
40
|
+
An [`AxisSelector`][haliax.AxisSelector] accepts either an `Axis` object or just the axis name as a string. It is used
|
|
41
|
+
whenever a function can read the axis size from one of its arguments. This mirrors how NumPy lets you pass `axis=0` when
|
|
42
|
+
reducing an array:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
total = x.sum(axis=Batch) # using the Axis handle
|
|
46
|
+
same_total = x.sum(axis="batch") # using only the name
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Strings are convenient when you only care about the name, but `Axis` objects still work so you can keep using the handles
|
|
50
|
+
you created earlier. If an axis with that name is missing, Haliax raises a `ValueError`.
|
|
51
|
+
|
|
52
|
+
### AxisSpec
|
|
53
|
+
|
|
54
|
+
An [`AxisSpec`][haliax.AxisSpec] is used when Haliax needs full size information to create or reshape an array. You can
|
|
55
|
+
provide a shape dictionary (sometimes called a "shape dict") that maps names to sizes, or a sequence of `Axis` objects:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
shape = {"batch": 32, "feature": 128}
|
|
59
|
+
y = hax.zeros(shape) # using a shape dict
|
|
60
|
+
z = hax.zeros((Batch, Feature)) # using the Axis objects directly
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Both forms describe the same layout. Python dictionaries preserve insertion order, so the ordering in a shape dict matches
|
|
64
|
+
the order that axes appear in the array. Sequences must contain `Axis` objects (not plain strings) because Haliax cannot
|
|
65
|
+
otherwise know the axis sizes.
|
|
66
|
+
|
|
67
|
+
### AxisSelection
|
|
68
|
+
|
|
69
|
+
[`AxisSelection`][haliax.AxisSelection] generalizes the previous aliases so you can talk about several axes at once. It
|
|
70
|
+
shows up in reductions, indexing helpers, axis-mapping utilities, and anywhere you might have written `axis=(0, 1)` in
|
|
71
|
+
NumPy. You may supply:
|
|
72
|
+
|
|
73
|
+
* a sequence mixing `Axis` objects and strings, e.g. `("batch", Feature)` when reducing two axes,
|
|
74
|
+
* an `AxisSpec`, which is handy when you already have a tuple of `Axis` objects, or
|
|
75
|
+
* a "partial shape dict" where the values are either sizes or `None` to indicate "any size". Dictionaries are useful when
|
|
76
|
+
you only care about a subset of axes or want to assert a particular size.
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
# Reduce over two axes using a tuple of selectors.
|
|
80
|
+
scalar = x.sum(axis=("batch", Feature))
|
|
81
|
+
|
|
82
|
+
# Ask for the axes by name and optionally pin sizes.
|
|
83
|
+
x.resolve_axis({"batch": None, "feature": None}) # returns {"batch": 32, "feature": 128}
|
|
84
|
+
|
|
85
|
+
from haliax.axis import selects_axis
|
|
86
|
+
assert selects_axis((Batch, "feature"), {"batch": None, "feature": 128})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Occasionally, an axis size can be inferred in some circumstances but not others. When this happens we still use
|
|
90
|
+
`AxisSelector` (or `AxisSelection` for multiple axes) but document the behavior in the docstring. A `RuntimeError` will be
|
|
91
|
+
raised if the size cannot be inferred.
|
|
22
92
|
|
|
23
93
|
::: haliax.Axis
|
|
24
94
|
::: haliax.AxisSelector
|
|
@@ -289,6 +359,49 @@ These are all more or less directly from JAX's NumPy API.
|
|
|
289
359
|
::: haliax.triu
|
|
290
360
|
::: haliax.where
|
|
291
361
|
|
|
362
|
+
### FFT
|
|
363
|
+
|
|
364
|
+
All FFT helpers accept an ``axis`` argument which may be a single axis, its
|
|
365
|
+
name, or an ordered mapping from axes to output sizes. Passing a mapping
|
|
366
|
+
dispatches to the ``n``‑dimensional variants in :mod:`jax.numpy.fft`.
|
|
367
|
+
|
|
368
|
+
For example::
|
|
369
|
+
|
|
370
|
+
import jax.numpy as jnp
|
|
371
|
+
import haliax as hax
|
|
372
|
+
|
|
373
|
+
T = hax.Axis("time", 8)
|
|
374
|
+
signal = hax.arange(T, dtype=jnp.float32)
|
|
375
|
+
|
|
376
|
+
# operate along a single axis specified by name
|
|
377
|
+
hax.fft(signal, axis="time")
|
|
378
|
+
|
|
379
|
+
# resize by passing an Axis object
|
|
380
|
+
hax.fft(signal, axis=hax.Axis("time", 16))
|
|
381
|
+
|
|
382
|
+
X, Y = hax.make_axes(X=4, Y=6)
|
|
383
|
+
image = hax.arange((X, Y), dtype=jnp.float32)
|
|
384
|
+
|
|
385
|
+
# transform across several axes in order by passing a sequence
|
|
386
|
+
hax.fft(image, axis=("X", "Y"))
|
|
387
|
+
|
|
388
|
+
# selectively resize axes by providing a mapping
|
|
389
|
+
hax.fft(image, axis={"X": None, "Y": hax.Axis("Y", 10)})
|
|
390
|
+
|
|
391
|
+
# mappings can cover just a subset of axes when only partial resizing is needed
|
|
392
|
+
hax.fft(image, axis={"Y": 10})
|
|
393
|
+
|
|
394
|
+
::: haliax.fft
|
|
395
|
+
::: haliax.ifft
|
|
396
|
+
::: haliax.hfft
|
|
397
|
+
::: haliax.ihfft
|
|
398
|
+
::: haliax.rfft
|
|
399
|
+
::: haliax.irfft
|
|
400
|
+
::: haliax.fftfreq
|
|
401
|
+
::: haliax.rfftfreq
|
|
402
|
+
::: haliax.fftshift
|
|
403
|
+
::: haliax.ifftshift
|
|
404
|
+
|
|
292
405
|
|
|
293
406
|
|
|
294
407
|
## Named Array Reference
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Haliax Primer
|
|
2
|
+
|
|
3
|
+
Haliax provides named tensors built on top of JAX. This primer is written for LLM agents and other downstream libraries and collects the core ideas for quick reference.
|
|
4
|
+
|
|
5
|
+
## Axes and Named Arrays
|
|
6
|
+
|
|
7
|
+
Arrays are indexed by `Axis` objects. You can define them explicitly or generate several with `make_axes`.
|
|
8
|
+
You may also specify shapes with a **shape dict**, mapping axis names to sizes.
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
import haliax as hax
|
|
12
|
+
from haliax import Axis
|
|
13
|
+
|
|
14
|
+
Batch = Axis("batch", 4)
|
|
15
|
+
Feature = Axis("feature", 8)
|
|
16
|
+
# or: Batch, Feature = hax.make_axes(batch=4, feature=8)
|
|
17
|
+
# using Axis objects
|
|
18
|
+
x = hax.zeros((Batch, Feature))
|
|
19
|
+
# or using a shape dict
|
|
20
|
+
shape = {"batch": 4, "feature": 8}
|
|
21
|
+
x = hax.zeros(shape)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Most functions accept either axes or shape dicts interchangeably.
|
|
25
|
+
|
|
26
|
+
A tensor with named axes is a [`NamedArray`][haliax.NamedArray]. Elementwise operations mirror `jax.numpy` but accept named axes.
|
|
27
|
+
|
|
28
|
+
### Ways to Describe Axes
|
|
29
|
+
|
|
30
|
+
If you're used to `axis=0` style code in NumPy or JAX, think of Haliax as swapping those positional indices for names
|
|
31
|
+
like `axis="batch"`. The API hints refer to a few helper aliases; this table shows how they map back to familiar
|
|
32
|
+
concepts:
|
|
33
|
+
|
|
34
|
+
| Name | Accepts | Typical use | Example |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| [`Axis`][haliax.Axis] | `Axis(name: str, size: int)` | Define a named dimension with a fixed size | `Batch = Axis("batch", 32)` |
|
|
37
|
+
| [`AxisSelector`][haliax.AxisSelector] | `Axis` or `str` | Refer to an existing axis when the size can be inferred from the argument | `x.sum(axis="batch")` |
|
|
38
|
+
| [`AxisSpec`][haliax.AxisSpec] | `dict[str, int]`, `Axis`, or a sequence of `Axis` objects | Supply complete shape information (array creation, reshaping) | `hax.zeros((Batch, Feature))` |
|
|
39
|
+
| [`AxisSelection`][haliax.AxisSelection] | `dict[str, int | None]`, `AxisSpec`, or a sequence of `AxisSelector` values | Work with one or more existing axes (reductions, indexing helpers, flattening, …) | `x.sum(axis=("batch", Feature))` |
|
|
40
|
+
|
|
41
|
+
The following sections expand on each alias with quick references and NumPy-style parallels.
|
|
42
|
+
|
|
43
|
+
#### `Axis`: reusable named dimensions
|
|
44
|
+
|
|
45
|
+
An [`Axis`][haliax.Axis] stores a `name` and a `size`. Create them directly or let
|
|
46
|
+
[`haliax.make_axes`][] build a handful at once. Because axes compare by both name and size, they act as reusable handles and
|
|
47
|
+
catch many wiring mistakes early.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
Batch = Axis("batch", 32)
|
|
51
|
+
Feature = Axis("feature", 128)
|
|
52
|
+
x = hax.ones((Batch, Feature))
|
|
53
|
+
print(Batch.name, Batch.size)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### `AxisSelector`: when the size is already known
|
|
57
|
+
|
|
58
|
+
Many functions already see the array whose axes you're referencing (e.g. reductions). In those cases you can pass either the
|
|
59
|
+
`Axis` object or simply the axis name as a string. Haliax resolves the name against the array, similar to `axis=0` in NumPy.
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
total = x.sum(axis=Batch) # use the Axis handle
|
|
63
|
+
same_total = x.sum(axis="batch") # or just the name
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If you reference an axis name that isn't present, Haliax raises a `ValueError`.
|
|
67
|
+
|
|
68
|
+
#### `AxisSpec`: describing complete shapes
|
|
69
|
+
|
|
70
|
+
When Haliax needs explicit sizes—creating arrays, reshaping, broadcasting to a new axis—you provide an [`AxisSpec`][haliax.AxisSpec].
|
|
71
|
+
Shape dictionaries keep things close to standard Python, while sequences require actual `Axis` objects so the sizes stay explicit.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
shape = {"batch": 32, "feature": 128}
|
|
75
|
+
y = hax.zeros(shape) # using a shape dict
|
|
76
|
+
z = hax.zeros((Batch, Feature)) # or a sequence of Axis objects
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Python dictionaries preserve insertion order, so the layout in a shape dict matches the order of axes in the resulting array.
|
|
80
|
+
|
|
81
|
+
#### `AxisSelection`: several axes at once
|
|
82
|
+
|
|
83
|
+
[`AxisSelection`][haliax.AxisSelection] is the plural form used by reductions, indexing helpers, and flattening utilities. Supply a
|
|
84
|
+
tuple mixing `Axis` objects and strings, reuse an existing `AxisSpec`, or pass a partial shape dict where values are either
|
|
85
|
+
sizes or `None` for "any size".
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
scalar = x.sum(axis=("batch", Feature))
|
|
89
|
+
|
|
90
|
+
# Ask for the axes by name and optionally pin sizes.
|
|
91
|
+
x.resolve_axis({"batch": None, "feature": None}) # returns {"batch": 32, "feature": 128}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Partial shape dicts shine when you only care about a subset of axes or want assertions about their sizes. If the axis size
|
|
95
|
+
cannot be inferred from the provided arguments, Haliax raises a `RuntimeError`.
|
|
96
|
+
|
|
97
|
+
## Indexing and Broadcasting
|
|
98
|
+
|
|
99
|
+
Use axis names when slicing. Dictionaries are convenient for several axes:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
first = x["batch", 0]
|
|
103
|
+
sub = x["batch", 1:3]
|
|
104
|
+
# or with a dict
|
|
105
|
+
first = x[{"batch": 0}]
|
|
106
|
+
sub = x[{"batch": slice(1, 3)}]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Axes broadcast by matching names. `broadcast_axis` adds a new axis to an array:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
row = hax.arange(Feature)
|
|
113
|
+
outer = row.broadcast_axis(Batch) * hax.arange(Batch)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
See [Indexing and Slicing](indexing.md) and [Broadcasting](broadcasting.md) for details.
|
|
117
|
+
|
|
118
|
+
## Rearranging Axes
|
|
119
|
+
|
|
120
|
+
`rearrange` changes axis order and can merge or split axes using einops‑style syntax. It is useful when interfacing with positional APIs.
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# transpose features and batch
|
|
124
|
+
x_t = hax.rearrange(x, "batch feature -> feature batch")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
More examples appear in [Rearrange](rearrange.md).
|
|
128
|
+
|
|
129
|
+
## Matrix Multiplication
|
|
130
|
+
|
|
131
|
+
`dot` contracts over named axes while preserving order independence.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
Weight = Axis("weight", 8)
|
|
135
|
+
w = hax.ones((Feature, Weight))
|
|
136
|
+
prod = hax.dot(x, w, axis=Feature)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
For more complex contractions use [`einsum`][haliax.einsum]. See [Matrix Multiplication](matmul.md).
|
|
140
|
+
|
|
141
|
+
## Scans and Folds
|
|
142
|
+
|
|
143
|
+
Use [`scan`][haliax.scan] or [`fold`][haliax.fold] to apply a function along an axis with optional gradient checkpointing.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
Time = Axis("time", 10)
|
|
147
|
+
sequence = hax.ones((Time, Feature))
|
|
148
|
+
|
|
149
|
+
def add(prev, cur):
|
|
150
|
+
return prev + cur
|
|
151
|
+
|
|
152
|
+
result = hax.fold(add, Time)(hax.zeros((Feature,)), sequence)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
See [Scan and Fold](scan.md) for checkpointing policies and stacked modules.
|
|
156
|
+
|
|
157
|
+
## Partitioning
|
|
158
|
+
|
|
159
|
+
Arrays and modules can be distributed across devices by mapping named axes to mesh axes:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
with hax.axis_mapping({"batch": "data"}):
|
|
163
|
+
sharded = hax.shard(x)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The [Partitioning](partitioning.md) guide explains how to set up device meshes and shard arrays.
|
|
167
|
+
|
|
168
|
+
## Typing Support
|
|
169
|
+
|
|
170
|
+
Type annotations use `haliax.haxtyping` which extends `jaxtyping`:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
import haliax.haxtyping as ht
|
|
174
|
+
|
|
175
|
+
def f(t: ht.Float[hax.NamedArray, "batch feature"]):
|
|
176
|
+
...
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
See [Typing](typing.md) for matching runtime checks and dtype-aware annotations.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
This primer highlights common patterns. The [cheatsheet](cheatsheet.md) lists many additional conversions from JAX to Haliax.
|
|
@@ -96,6 +96,18 @@ from .ops import (
|
|
|
96
96
|
bincount,
|
|
97
97
|
where,
|
|
98
98
|
)
|
|
99
|
+
from .fft import (
|
|
100
|
+
fft,
|
|
101
|
+
fftfreq,
|
|
102
|
+
fftshift,
|
|
103
|
+
hfft,
|
|
104
|
+
ifft,
|
|
105
|
+
ifftshift,
|
|
106
|
+
ihfft,
|
|
107
|
+
irfft,
|
|
108
|
+
rfft,
|
|
109
|
+
rfftfreq,
|
|
110
|
+
)
|
|
99
111
|
from .partitioning import auto_sharded, axis_mapping, fsdp, named_jit, shard, shard_with_axis_mapping
|
|
100
112
|
from .specialized_fns import top_k
|
|
101
113
|
from .types import Scalar
|
|
@@ -1214,6 +1226,16 @@ __all__ = [
|
|
|
1214
1226
|
"clip",
|
|
1215
1227
|
"tril",
|
|
1216
1228
|
"triu",
|
|
1229
|
+
"fft",
|
|
1230
|
+
"ifft",
|
|
1231
|
+
"hfft",
|
|
1232
|
+
"ihfft",
|
|
1233
|
+
"rfft",
|
|
1234
|
+
"irfft",
|
|
1235
|
+
"fftfreq",
|
|
1236
|
+
"rfftfreq",
|
|
1237
|
+
"fftshift",
|
|
1238
|
+
"ifftshift",
|
|
1217
1239
|
"add",
|
|
1218
1240
|
"arctan2",
|
|
1219
1241
|
"bitwise_and",
|