extended-einsum 0.1.0__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.
- extended_einsum-0.1.0/LICENSE +21 -0
- extended_einsum-0.1.0/PKG-INFO +139 -0
- extended_einsum-0.1.0/README.md +104 -0
- extended_einsum-0.1.0/pyproject.toml +85 -0
- extended_einsum-0.1.0/src/extended_einsum/__init__.py +43 -0
- extended_einsum-0.1.0/src/extended_einsum/backend_translation/__init__.py +7 -0
- extended_einsum-0.1.0/src/extended_einsum/backend_translation/backend.py +110 -0
- extended_einsum-0.1.0/src/extended_einsum/backend_translation/runtime.py +21 -0
- extended_einsum-0.1.0/src/extended_einsum/backend_translation/translate.py +760 -0
- extended_einsum-0.1.0/src/extended_einsum/backends/__init__.py +1 -0
- extended_einsum-0.1.0/src/extended_einsum/backends/jax.py +128 -0
- extended_einsum-0.1.0/src/extended_einsum/backends/numpy.py +130 -0
- extended_einsum-0.1.0/src/extended_einsum/backends/registry.py +41 -0
- extended_einsum-0.1.0/src/extended_einsum/backends/torch.py +158 -0
- extended_einsum-0.1.0/src/extended_einsum/interface/__init__.py +35 -0
- extended_einsum-0.1.0/src/extended_einsum/interface/functions.py +173 -0
- extended_einsum-0.1.0/src/extended_einsum/interface/operator.py +63 -0
- extended_einsum-0.1.0/src/extended_einsum/interface/tensor_expression.py +333 -0
- extended_einsum-0.1.0/src/extended_einsum/language/__init__.py +1 -0
- extended_einsum-0.1.0/src/extended_einsum/language/core.py +28 -0
- extended_einsum-0.1.0/src/extended_einsum/language/rich_instruction.py +18 -0
- extended_einsum-0.1.0/src/extended_einsum/language/rich_operators.py +437 -0
- extended_einsum-0.1.0/src/extended_einsum/language/rich_program.py +62 -0
- extended_einsum-0.1.0/src/extended_einsum/language/types.py +30 -0
- extended_einsum-0.1.0/src/extended_einsum/preprocess.py +2382 -0
- extended_einsum-0.1.0/src/extended_einsum/py.typed +0 -0
- extended_einsum-0.1.0/src/extended_einsum/shapes.py +89 -0
- extended_einsum-0.1.0/src/extended_einsum/utils.py +73 -0
- extended_einsum-0.1.0/src/extended_einsum/visualization.py +648 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FSU Theoretical Computer Science II
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: extended-einsum
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Build, optimize, and execute numerically stable extended Einstein summation expressions with PyTorch, NumPy, and optional JAX.
|
|
5
|
+
Keywords: einsum,machine-learning,probabilistic circuits,tensor
|
|
6
|
+
Author: Christoph Staudt, Maurice Wenig
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Dist: numpy>=2.1.6
|
|
20
|
+
Requires-Dist: sesum>=0.4.0
|
|
21
|
+
Requires-Dist: torch>=2.12.0
|
|
22
|
+
Requires-Dist: jax>=0.10.1 ; extra == 'jax'
|
|
23
|
+
Requires-Dist: jax[cuda13]>=0.10.1 ; extra == 'jax-cuda'
|
|
24
|
+
Requires-Dist: matplotlib>=3.10.9 ; extra == 'visualization'
|
|
25
|
+
Requires-Dist: networkx>=3.6.1 ; extra == 'visualization'
|
|
26
|
+
Requires-Python: >=3.12
|
|
27
|
+
Project-URL: Homepage, https://github.com/ti2-group/extended_einsum
|
|
28
|
+
Project-URL: Repository, https://github.com/ti2-group/extended_einsum
|
|
29
|
+
Project-URL: Issues, https://github.com/ti2-group/extended_einsum/issues
|
|
30
|
+
Project-URL: Changelog, https://github.com/ti2-group/extended_einsum/blob/main/CHANGELOG.md
|
|
31
|
+
Provides-Extra: jax
|
|
32
|
+
Provides-Extra: jax-cuda
|
|
33
|
+
Provides-Extra: visualization
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# extended-einsum
|
|
37
|
+
|
|
38
|
+
[](https://github.com/ti2-group/extended_einsum/actions/workflows/ci.yml)
|
|
39
|
+
[](https://pypi.org/project/extended-einsum/)
|
|
40
|
+
[](https://pypi.org/project/extended-einsum/)
|
|
41
|
+
[](https://github.com/ti2-group/extended_einsum/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
`extended-einsum` builds tensor-expression graphs, rewrites contraction programs, and executes them with numerically stable evaluation strategies. PyTorch is the primary backend; NumPy is included in the base installation and JAX is optional.
|
|
44
|
+
|
|
45
|
+
The package is an expression engine, not a drop-in replacement for `torch.einsum` or `numpy.einsum`. Wrap backend arrays with `xe.array`, compose operations lazily, then call `materialize`.
|
|
46
|
+
|
|
47
|
+
> **Status:** `0.1.0` is an alpha release. The public expression API is usable, but indexing and some operators or stability-mode combinations are not implemented yet.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
Python 3.12, 3.13, and 3.14 are supported.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install extended-einsum
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Optional features are installed explicitly:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install "extended-einsum[jax]"
|
|
61
|
+
pip install "extended-einsum[jax-cuda]"
|
|
62
|
+
pip install "extended-einsum[visualization]"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The CUDA extra follows JAX's CUDA 13 installation. PyTorch device support is determined by the PyTorch build available from your configured package index.
|
|
66
|
+
|
|
67
|
+
## Quickstart
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import torch
|
|
71
|
+
import extended_einsum as xe
|
|
72
|
+
|
|
73
|
+
left_torch = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
|
|
74
|
+
right_torch = torch.tensor([[2.0, 0.0], [1.0, 2.0]])
|
|
75
|
+
|
|
76
|
+
left = xe.array(left_torch)
|
|
77
|
+
right = xe.array(right_torch)
|
|
78
|
+
expression = xe.einsum("ik,kj->ij", xe.exp(left), right)
|
|
79
|
+
result = expression.materialize(stability_mode="unstable")
|
|
80
|
+
|
|
81
|
+
assert torch.allclose(
|
|
82
|
+
result.backend_array,
|
|
83
|
+
torch.einsum("ik,kj->ij", torch.exp(left_torch), right_torch),
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The same interface accepts NumPy arrays. With the `jax` extra installed it also accepts JAX arrays:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import numpy as np
|
|
91
|
+
import extended_einsum as xe
|
|
92
|
+
|
|
93
|
+
source = xe.array(np.arange(6.0).reshape(2, 3))
|
|
94
|
+
result = xe.softmax(source, axis=1).materialize()
|
|
95
|
+
print(result.backend_array)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Expressions and stability
|
|
99
|
+
|
|
100
|
+
The public interface currently includes:
|
|
101
|
+
|
|
102
|
+
- `array`, `einsum`, `stack`, `take`, `slice`, and `select`
|
|
103
|
+
- `exp`, `log`, `sin`, `cos`, `tan`, `sqrt`, `inverse`, and `softmax`
|
|
104
|
+
- `TensorExpression.materialize` and `extract_program`
|
|
105
|
+
|
|
106
|
+
Supported execution backends are PyTorch, NumPy, and optional JAX. Rich programs can be evaluated in `unstable`, `scaled_min`, `scaled_sum`, `logspace_min`, or `logspace_max` mode. Support is operator-dependent; unsupported combinations raise `NotImplementedError` instead of silently changing semantics.
|
|
107
|
+
|
|
108
|
+
The preprocessing API also provides expression folding and contraction-path optimization. DAG plotting is available from `extended_einsum.visualization` when the visualization extra is installed.
|
|
109
|
+
|
|
110
|
+
## Examples
|
|
111
|
+
|
|
112
|
+
All introductory scripts in [`examples/`](https://github.com/ti2-group/extended_einsum/tree/main/examples) are standalone: copy one into another project with `extended-einsum` installed and run it from any working directory.
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
python examples/torch_quickstart.py
|
|
116
|
+
python examples/numpy_backend.py
|
|
117
|
+
python examples/stable_materialization.py
|
|
118
|
+
python examples/jax_backend.py # requires [jax]
|
|
119
|
+
python examples/visualize_expression.py graph.png # requires [visualization]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The advanced [`demo/cirkit.py`](https://github.com/ti2-group/extended_einsum/blob/main/demo/cirkit.py) integration is also standalone, but requires the repository demo dependencies and currently Python 3.12 or 3.13 because of Cirkit's SciPy constraint. Its defaults use a small synthetic circuit; training and benchmark sweeps are opt-in. Generated benchmark data and plots are repository artifacts and are never included in distributions.
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
This project uses [uv](https://docs.astral.sh/uv/):
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
uv sync --group dev --group demo --extra jax --extra visualization
|
|
130
|
+
uv run ruff check .
|
|
131
|
+
uv run pytest
|
|
132
|
+
uv build
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
See [CONTRIBUTING.md](https://github.com/ti2-group/extended_einsum/blob/main/CONTRIBUTING.md) for development details and [PUBLISHING.md](https://github.com/ti2-group/extended_einsum/blob/main/PUBLISHING.md) for the release process.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
Copyright © 2026 FSU Theoretical Computer Science II. Distributed under the [MIT License](https://github.com/ti2-group/extended_einsum/blob/main/LICENSE).
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# extended-einsum
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ti2-group/extended_einsum/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/extended-einsum/)
|
|
5
|
+
[](https://pypi.org/project/extended-einsum/)
|
|
6
|
+
[](https://github.com/ti2-group/extended_einsum/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
`extended-einsum` builds tensor-expression graphs, rewrites contraction programs, and executes them with numerically stable evaluation strategies. PyTorch is the primary backend; NumPy is included in the base installation and JAX is optional.
|
|
9
|
+
|
|
10
|
+
The package is an expression engine, not a drop-in replacement for `torch.einsum` or `numpy.einsum`. Wrap backend arrays with `xe.array`, compose operations lazily, then call `materialize`.
|
|
11
|
+
|
|
12
|
+
> **Status:** `0.1.0` is an alpha release. The public expression API is usable, but indexing and some operators or stability-mode combinations are not implemented yet.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Python 3.12, 3.13, and 3.14 are supported.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install extended-einsum
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Optional features are installed explicitly:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install "extended-einsum[jax]"
|
|
26
|
+
pip install "extended-einsum[jax-cuda]"
|
|
27
|
+
pip install "extended-einsum[visualization]"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The CUDA extra follows JAX's CUDA 13 installation. PyTorch device support is determined by the PyTorch build available from your configured package index.
|
|
31
|
+
|
|
32
|
+
## Quickstart
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import torch
|
|
36
|
+
import extended_einsum as xe
|
|
37
|
+
|
|
38
|
+
left_torch = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
|
|
39
|
+
right_torch = torch.tensor([[2.0, 0.0], [1.0, 2.0]])
|
|
40
|
+
|
|
41
|
+
left = xe.array(left_torch)
|
|
42
|
+
right = xe.array(right_torch)
|
|
43
|
+
expression = xe.einsum("ik,kj->ij", xe.exp(left), right)
|
|
44
|
+
result = expression.materialize(stability_mode="unstable")
|
|
45
|
+
|
|
46
|
+
assert torch.allclose(
|
|
47
|
+
result.backend_array,
|
|
48
|
+
torch.einsum("ik,kj->ij", torch.exp(left_torch), right_torch),
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The same interface accepts NumPy arrays. With the `jax` extra installed it also accepts JAX arrays:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import numpy as np
|
|
56
|
+
import extended_einsum as xe
|
|
57
|
+
|
|
58
|
+
source = xe.array(np.arange(6.0).reshape(2, 3))
|
|
59
|
+
result = xe.softmax(source, axis=1).materialize()
|
|
60
|
+
print(result.backend_array)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Expressions and stability
|
|
64
|
+
|
|
65
|
+
The public interface currently includes:
|
|
66
|
+
|
|
67
|
+
- `array`, `einsum`, `stack`, `take`, `slice`, and `select`
|
|
68
|
+
- `exp`, `log`, `sin`, `cos`, `tan`, `sqrt`, `inverse`, and `softmax`
|
|
69
|
+
- `TensorExpression.materialize` and `extract_program`
|
|
70
|
+
|
|
71
|
+
Supported execution backends are PyTorch, NumPy, and optional JAX. Rich programs can be evaluated in `unstable`, `scaled_min`, `scaled_sum`, `logspace_min`, or `logspace_max` mode. Support is operator-dependent; unsupported combinations raise `NotImplementedError` instead of silently changing semantics.
|
|
72
|
+
|
|
73
|
+
The preprocessing API also provides expression folding and contraction-path optimization. DAG plotting is available from `extended_einsum.visualization` when the visualization extra is installed.
|
|
74
|
+
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
All introductory scripts in [`examples/`](https://github.com/ti2-group/extended_einsum/tree/main/examples) are standalone: copy one into another project with `extended-einsum` installed and run it from any working directory.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python examples/torch_quickstart.py
|
|
81
|
+
python examples/numpy_backend.py
|
|
82
|
+
python examples/stable_materialization.py
|
|
83
|
+
python examples/jax_backend.py # requires [jax]
|
|
84
|
+
python examples/visualize_expression.py graph.png # requires [visualization]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The advanced [`demo/cirkit.py`](https://github.com/ti2-group/extended_einsum/blob/main/demo/cirkit.py) integration is also standalone, but requires the repository demo dependencies and currently Python 3.12 or 3.13 because of Cirkit's SciPy constraint. Its defaults use a small synthetic circuit; training and benchmark sweeps are opt-in. Generated benchmark data and plots are repository artifacts and are never included in distributions.
|
|
88
|
+
|
|
89
|
+
## Development
|
|
90
|
+
|
|
91
|
+
This project uses [uv](https://docs.astral.sh/uv/):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
uv sync --group dev --group demo --extra jax --extra visualization
|
|
95
|
+
uv run ruff check .
|
|
96
|
+
uv run pytest
|
|
97
|
+
uv build
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
See [CONTRIBUTING.md](https://github.com/ti2-group/extended_einsum/blob/main/CONTRIBUTING.md) for development details and [PUBLISHING.md](https://github.com/ti2-group/extended_einsum/blob/main/PUBLISHING.md) for the release process.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
Copyright © 2026 FSU Theoretical Computer Science II. Distributed under the [MIT License](https://github.com/ti2-group/extended_einsum/blob/main/LICENSE).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "extended-einsum"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Build, optimize, and execute numerically stable extended Einstein summation expressions with PyTorch, NumPy, and optional JAX."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Christoph Staudt" },
|
|
11
|
+
{ name = "Maurice Wenig" },
|
|
12
|
+
]
|
|
13
|
+
keywords = [
|
|
14
|
+
"einsum",
|
|
15
|
+
"machine-learning",
|
|
16
|
+
"probabilistic circuits",
|
|
17
|
+
"tensor",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Intended Audience :: Science/Research",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Programming Language :: Python :: 3.14",
|
|
27
|
+
"Topic :: Scientific/Engineering",
|
|
28
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"numpy>=2.1.6",
|
|
33
|
+
"sesum>=0.4.0",
|
|
34
|
+
"torch>=2.12.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
jax = ["jax>=0.10.1"]
|
|
39
|
+
jax-cuda = ["jax[cuda13]>=0.10.1"]
|
|
40
|
+
visualization = [
|
|
41
|
+
"matplotlib>=3.10.9",
|
|
42
|
+
"networkx>=3.6.1",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.urls]
|
|
46
|
+
Homepage = "https://github.com/ti2-group/extended_einsum"
|
|
47
|
+
Repository = "https://github.com/ti2-group/extended_einsum"
|
|
48
|
+
Issues = "https://github.com/ti2-group/extended_einsum/issues"
|
|
49
|
+
Changelog = "https://github.com/ti2-group/extended_einsum/blob/main/CHANGELOG.md"
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["uv_build>=0.11.19,<0.12.0"]
|
|
53
|
+
build-backend = "uv_build"
|
|
54
|
+
|
|
55
|
+
[tool.uv]
|
|
56
|
+
constraint-dependencies = [
|
|
57
|
+
"numpy>=2.3.0; python_version >= '3.14'",
|
|
58
|
+
"scipy>=1.17.0; python_version >= '3.14'",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[dependency-groups]
|
|
62
|
+
demo = [
|
|
63
|
+
"libcirkit>=0.2.1; python_version < '3.14'",
|
|
64
|
+
"matplotlib>=3.10.9",
|
|
65
|
+
"networkx>=3.6.1",
|
|
66
|
+
"pandas>=2.3.3",
|
|
67
|
+
"seaborn>=0.13.2",
|
|
68
|
+
"torchvision>=0.27.0",
|
|
69
|
+
]
|
|
70
|
+
dev = [
|
|
71
|
+
"pytest>=9.1.1",
|
|
72
|
+
"ruff>=0.6.0",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[tool.ruff]
|
|
76
|
+
line-length = 200
|
|
77
|
+
target-version = "py312"
|
|
78
|
+
|
|
79
|
+
[tool.ruff.lint]
|
|
80
|
+
select = ["E", "F", "I"]
|
|
81
|
+
|
|
82
|
+
[tool.ruff.format]
|
|
83
|
+
quote-style = "double"
|
|
84
|
+
indent-style = "space"
|
|
85
|
+
line-ending = "lf"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
|
|
3
|
+
from extended_einsum.interface import TensorExpression as TensorExpression
|
|
4
|
+
from extended_einsum.interface import array as array
|
|
5
|
+
from extended_einsum.interface import cos as cos
|
|
6
|
+
from extended_einsum.interface import einsum as einsum
|
|
7
|
+
from extended_einsum.interface import exp as exp
|
|
8
|
+
from extended_einsum.interface import extract_program as extract_program
|
|
9
|
+
from extended_einsum.interface import inverse as inverse
|
|
10
|
+
from extended_einsum.interface import log as log
|
|
11
|
+
from extended_einsum.interface import select as select
|
|
12
|
+
from extended_einsum.interface import sin as sin
|
|
13
|
+
from extended_einsum.interface import slice as slice
|
|
14
|
+
from extended_einsum.interface import softmax as softmax
|
|
15
|
+
from extended_einsum.interface import sqrt as sqrt
|
|
16
|
+
from extended_einsum.interface import stack as stack
|
|
17
|
+
from extended_einsum.interface import take as take
|
|
18
|
+
from extended_einsum.interface import tan as tan
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
__version__ = version("extended-einsum")
|
|
22
|
+
except PackageNotFoundError:
|
|
23
|
+
__version__ = "0.1.0.dev0"
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"TensorExpression",
|
|
27
|
+
"__version__",
|
|
28
|
+
"array",
|
|
29
|
+
"cos",
|
|
30
|
+
"einsum",
|
|
31
|
+
"exp",
|
|
32
|
+
"extract_program",
|
|
33
|
+
"inverse",
|
|
34
|
+
"log",
|
|
35
|
+
"select",
|
|
36
|
+
"sin",
|
|
37
|
+
"slice",
|
|
38
|
+
"softmax",
|
|
39
|
+
"sqrt",
|
|
40
|
+
"stack",
|
|
41
|
+
"take",
|
|
42
|
+
"tan",
|
|
43
|
+
]
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from .backend import BackendArray as BackendArray
|
|
2
|
+
from .backend import BackendCompiler as BackendCompiler
|
|
3
|
+
from .backend import BackendFunctions as BackendFunctions
|
|
4
|
+
from .backend import BackendProgram as BackendProgram
|
|
5
|
+
from .backend import get_backend_of_array as get_backend_of_array
|
|
6
|
+
from .runtime import run_program as run_program
|
|
7
|
+
from .translate import translate_to_backend_program as translate_to_backend_program
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Callable, Generic, Protocol, TypeVar
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
from extended_einsum.language.types import Backend, HasShape
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BackendArray(Protocol):
|
|
12
|
+
@property
|
|
13
|
+
def shape(self) -> tuple[int, ...] | torch.Size: ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
TBackendArray = TypeVar("TBackendArray", bound=BackendArray)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BackendFunctions(Protocol[TBackendArray]):
|
|
20
|
+
@staticmethod
|
|
21
|
+
def stop_gradient(array: TBackendArray) -> TBackendArray: ...
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def exp(array: TBackendArray) -> TBackendArray: ...
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def log(array: TBackendArray) -> TBackendArray: ...
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def sum(array: TBackendArray, axis: int | tuple[int, ...] | None = None, keepdims: bool = False) -> TBackendArray: ...
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def max(array: TBackendArray, axis: int | tuple[int, ...] | None = None, keepdims: bool = False) -> TBackendArray: ...
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def min(array: TBackendArray, axis: int | tuple[int, ...] | None = None, keepdims: bool = False) -> TBackendArray: ...
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def maximum(array_1: TBackendArray, array_2: TBackendArray) -> TBackendArray: ...
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def reshape(array: TBackendArray, shape: tuple[int, ...]) -> TBackendArray: ...
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def broadcast_to(array: TBackendArray, shape: tuple[int, ...]) -> TBackendArray: ...
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def stack(arrays: Sequence[TBackendArray], axis: int) -> TBackendArray: ...
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def concat(arrays: Sequence[TBackendArray], axis: int) -> TBackendArray: ...
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def take(array: TBackendArray, indices: TBackendArray, axis: int) -> TBackendArray: ...
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def select(array: TBackendArray, axis: int, index: int) -> TBackendArray: ...
|
|
58
|
+
|
|
59
|
+
@staticmethod
|
|
60
|
+
def slice(array: TBackendArray, start: int, stop: int, axis: int) -> TBackendArray: ...
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def softmax(array: TBackendArray, axis: int | tuple[int, ...]) -> TBackendArray: ...
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def einsum(format_string: str, *operands: TBackendArray) -> TBackendArray: ...
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def add(summand_array_1: TBackendArray, summand_array_2: TBackendArray) -> TBackendArray: ...
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def subtract(minuend_array: TBackendArray, subtrahend_array: TBackendArray) -> TBackendArray: ...
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def multiply(factor_array_1: TBackendArray, factor_array_2: TBackendArray) -> TBackendArray: ...
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def divide(dividend_array: TBackendArray, divisor_array: TBackendArray) -> TBackendArray: ...
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(frozen=True)
|
|
82
|
+
class BackendProgram(Generic[TBackendArray]):
|
|
83
|
+
backend_calls: list[Callable[[Sequence[TBackendArray]], TBackendArray]]
|
|
84
|
+
call_arguments: list[tuple[int, ...]]
|
|
85
|
+
n_inputs: int
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class BackendCompiler(Protocol[TBackendArray]):
|
|
89
|
+
@staticmethod
|
|
90
|
+
def compile(
|
|
91
|
+
program: BackendProgram[TBackendArray],
|
|
92
|
+
inputs: Sequence[TBackendArray],
|
|
93
|
+
) -> Callable[[Sequence[TBackendArray]], TBackendArray]: ...
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_backend_of_array(array: HasShape) -> Backend:
|
|
97
|
+
if isinstance(array, torch.Tensor):
|
|
98
|
+
return "torch"
|
|
99
|
+
elif isinstance(array, np.ndarray):
|
|
100
|
+
return "numpy"
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
import jax
|
|
104
|
+
except ModuleNotFoundError:
|
|
105
|
+
jax = None # type: ignore[assignment]
|
|
106
|
+
|
|
107
|
+
if jax is not None and isinstance(array, jax.Array):
|
|
108
|
+
return "jax"
|
|
109
|
+
|
|
110
|
+
raise ValueError(f"Unsupported array type: {type(array)}")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from typing import TypeVar
|
|
3
|
+
|
|
4
|
+
from extended_einsum.backend_translation.backend import BackendArray, BackendProgram
|
|
5
|
+
|
|
6
|
+
TBackendArray = TypeVar("TBackendArray", bound=BackendArray)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def run_program(
|
|
10
|
+
program: BackendProgram[TBackendArray],
|
|
11
|
+
inputs: Sequence[TBackendArray],
|
|
12
|
+
) -> TBackendArray:
|
|
13
|
+
if len(inputs) != program.n_inputs:
|
|
14
|
+
raise ValueError(f"The number of inputs ({len(inputs)}) does not match the number of inputs ({program.n_inputs}) in the program.")
|
|
15
|
+
|
|
16
|
+
tensors: list[TBackendArray] = list(inputs)
|
|
17
|
+
for backend_call, argument_ids in zip(program.backend_calls, program.call_arguments):
|
|
18
|
+
argument_tensors = [tensors[argument] for argument in argument_ids]
|
|
19
|
+
result = backend_call(argument_tensors)
|
|
20
|
+
tensors.append(result)
|
|
21
|
+
return tensors[-1]
|