mlx-tomo 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.
- mlx_tomo-0.1.0/LICENSE +29 -0
- mlx_tomo-0.1.0/NOTICE +31 -0
- mlx_tomo-0.1.0/PKG-INFO +200 -0
- mlx_tomo-0.1.0/README.md +171 -0
- mlx_tomo-0.1.0/mlx_tomo/__init__.py +56 -0
- mlx_tomo-0.1.0/mlx_tomo/algorithms.py +193 -0
- mlx_tomo-0.1.0/mlx_tomo/api.py +122 -0
- mlx_tomo-0.1.0/mlx_tomo/filtering.py +254 -0
- mlx_tomo-0.1.0/mlx_tomo/geometry.py +220 -0
- mlx_tomo-0.1.0/mlx_tomo/phantom3d.py +148 -0
- mlx_tomo-0.1.0/mlx_tomo/projector.py +635 -0
- mlx_tomo-0.1.0/mlx_tomo/rays.py +179 -0
- mlx_tomo-0.1.0/mlx_tomo/ref.py +435 -0
- mlx_tomo-0.1.0/mlx_tomo/texture.py +269 -0
- mlx_tomo-0.1.0/mlx_tomo/tuning.py +61 -0
- mlx_tomo-0.1.0/mlx_tomo.egg-info/PKG-INFO +200 -0
- mlx_tomo-0.1.0/mlx_tomo.egg-info/SOURCES.txt +20 -0
- mlx_tomo-0.1.0/mlx_tomo.egg-info/dependency_links.txt +1 -0
- mlx_tomo-0.1.0/mlx_tomo.egg-info/requires.txt +5 -0
- mlx_tomo-0.1.0/mlx_tomo.egg-info/top_level.txt +1 -0
- mlx_tomo-0.1.0/pyproject.toml +46 -0
- mlx_tomo-0.1.0/setup.cfg +4 -0
mlx_tomo-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Martin Lachaine
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
9
|
+
this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
12
|
+
notice, this list of conditions and the following disclaimer in the
|
|
13
|
+
documentation and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
22
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
23
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
24
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
25
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
26
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
27
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
28
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
29
|
+
POSSIBILITY OF SUCH DAMAGE.
|
mlx_tomo-0.1.0/NOTICE
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
mlx-tomo
|
|
2
|
+
Copyright 2026 Martin Lachaine
|
|
3
|
+
|
|
4
|
+
mlx-tomo is an independent implementation of parallel-, fan- and cone-beam
|
|
5
|
+
X-ray projection and backprojection for Apple GPUs via Metal/MLX. It adopts the
|
|
6
|
+
geometry conventions, field names and sampling semantics of TIGRE so that
|
|
7
|
+
existing TIGRE workflows can be adapted with minimal API changes.
|
|
8
|
+
|
|
9
|
+
TIGRE is distributed under the BSD 3-Clause License:
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2015, University of Bath and CERN - European Organization for
|
|
12
|
+
Nuclear Research. All rights reserved.
|
|
13
|
+
|
|
14
|
+
https://github.com/CERN/TIGRE
|
|
15
|
+
|
|
16
|
+
The host-side geometry pipeline in mlx_tomo/ref.py and mlx_tomo/projector.py
|
|
17
|
+
implements the coordinate transforms that TIGRE's projector sources define
|
|
18
|
+
(computeDeltas, computeDeltas_parallel, eulerZYZ, rollPitchYaw), written from
|
|
19
|
+
those definitions in NumPy and Metal. TIGRE was used as a numerical reference
|
|
20
|
+
during development. No TIGRE source code is included in or redistributed by
|
|
21
|
+
this project.
|
|
22
|
+
|
|
23
|
+
If you use this software, please also cite TIGRE:
|
|
24
|
+
|
|
25
|
+
A. Biguri, M. Dosanjh, S. Hancock, and M. Soleimani, "TIGRE: a MATLAB-GPU
|
|
26
|
+
toolbox for CBCT image reconstruction," Biomedical Physics & Engineering
|
|
27
|
+
Express 2(5), 055010 (2016). doi:10.1088/2057-1976/2/5/055010
|
|
28
|
+
|
|
29
|
+
The three-dimensional Shepp-Logan ellipsoid table in mlx_tomo/phantom3d.py is
|
|
30
|
+
the standard modified Shepp-Logan phantom as published in the imaging
|
|
31
|
+
literature and as distributed by ODL (odl.phantom.shepp_logan).
|
mlx_tomo-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mlx-tomo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Parallel-, fan- and cone-beam X-ray projection and backprojection on Apple GPUs via Metal/MLX, with a TIGRE-compatible Python interface for supported operations
|
|
5
|
+
Author: Martin Lachaine
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/martinlachaine/mlx-tomo
|
|
8
|
+
Project-URL: Repository, https://github.com/martinlachaine/mlx-tomo
|
|
9
|
+
Project-URL: Issues, https://github.com/martinlachaine/mlx-tomo/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/martinlachaine/mlx-tomo/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: tomography,ct,cbct,cone-beam,projector,backprojector,radon-transform,drr,fdk,apple-silicon,metal,mlx,tigre
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
License-File: NOTICE
|
|
24
|
+
Requires-Dist: mlx==0.32.0
|
|
25
|
+
Requires-Dist: numpy>=2.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: scipy>=1.14; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# mlx-tomo
|
|
31
|
+
|
|
32
|
+
GPU-accelerated X-ray projection and backprojection for Apple silicon.
|
|
33
|
+
|
|
34
|
+
[](https://github.com/martinlachaine/mlx-tomo/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/mlx-tomo/)
|
|
36
|
+
[](https://github.com/martinlachaine/mlx-tomo/blob/main/LICENSE)
|
|
37
|
+
[](https://github.com/martinlachaine/mlx-tomo/blob/main/pyproject.toml)
|
|
38
|
+
[](#requirements-and-installation)
|
|
39
|
+
|
|
40
|
+
mlx-tomo provides parallel-beam, fan-beam, and cone-beam forward and
|
|
41
|
+
backprojection using custom Metal kernels through MLX. It offers a
|
|
42
|
+
TIGRE-compatible Python interface for supported operations, making it easier to
|
|
43
|
+
adapt existing tomography workflows to Apple GPUs.
|
|
44
|
+
|
|
45
|
+
Host-side geometry calculations use float64, while GPU computation uses float32.
|
|
46
|
+
Numerical accuracy is validated against an independent float64 reference
|
|
47
|
+
implementation, analytic ellipsoid projections, and impulse-placement tests.
|
|
48
|
+
|
|
49
|
+
The package includes projection operators, geometry utilities, and analytic FDK
|
|
50
|
+
and FBP reconstruction. Iterative and learned reconstruction algorithms are
|
|
51
|
+
intentionally outside its current scope.
|
|
52
|
+
|
|
53
|
+
mlx-tomo is research software and has not been validated for clinical or
|
|
54
|
+
diagnostic use.
|
|
55
|
+
|
|
56
|
+
## Requirements and installation
|
|
57
|
+
|
|
58
|
+
Requires an Apple silicon Mac (Metal/MLX) and Python 3.11 or newer.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install mlx-tomo
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Or install a tagged release from GitHub:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install "git+https://github.com/martinlachaine/mlx-tomo.git@v0.1.0"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`mlx` is pinned to a validated version; `numpy` has a lower bound. Check the
|
|
71
|
+
install with:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import numpy as np
|
|
75
|
+
import mlx_tomo
|
|
76
|
+
|
|
77
|
+
geo = mlx_tomo.geometry_default(high_resolution=False)
|
|
78
|
+
proj = mlx_tomo.Ax(np.ones(tuple(geo.nVoxel), np.float32), geo, np.array([0.0]))
|
|
79
|
+
print(mlx_tomo.__version__, proj.shape)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Development installation
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/martinlachaine/mlx-tomo && cd mlx-tomo
|
|
86
|
+
uv venv --python 3.13 .venv
|
|
87
|
+
uv pip install -p .venv/bin/python -e ".[dev]"
|
|
88
|
+
cd texture_bridge && ./build.sh && cd .. # optional texture backend
|
|
89
|
+
.venv/bin/python harness/run_tests.py # full correctness suite
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Quickstart
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import numpy as np
|
|
96
|
+
import mlx_tomo as tigre
|
|
97
|
+
|
|
98
|
+
geo = tigre.geometry_default(high_resolution=False) # 64^3 volume, 128^2 detector
|
|
99
|
+
vol = tigre.rasterize(geo, tigre.shepp_logan_mm(scale_mm=100.0))
|
|
100
|
+
|
|
101
|
+
angles = np.linspace(0, 2 * np.pi, 360, endpoint=False)
|
|
102
|
+
proj = tigre.Ax(vol, geo, angles, projection_type="interpolated")
|
|
103
|
+
rec = tigre.FDK(proj, geo, angles)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`proj` is `(n_angles, nDetector[0], nDetector[1])` float32 line integrals in
|
|
107
|
+
millimeter units; `rec` matches `geo.nVoxel` as `[z, y, x]`.
|
|
108
|
+
|
|
109
|
+
`examples/quickstart.py` runs cone and parallel projections and both
|
|
110
|
+
reconstructions end to end.
|
|
111
|
+
|
|
112
|
+
## API
|
|
113
|
+
|
|
114
|
+
| | |
|
|
115
|
+
|---|---|
|
|
116
|
+
| `geometry(mode=...)`, `geometry_default()` | geometry container |
|
|
117
|
+
| `Ax(img, geo, angles, projection_type)` | forward projection; `"interpolated"` or `"Siddon"` |
|
|
118
|
+
| `Atb(proj, geo, angles, backprojection_type)` | backprojection; `"FDK"` or `"matched"` |
|
|
119
|
+
| `Ax_rays`, `rays_from_geometry`, `affine_rays` | projection along user-supplied rays |
|
|
120
|
+
| `FDK`, `FBP`, `filtering` | analytic reconstruction; ramp filters, windows, Parker weights |
|
|
121
|
+
| `TextureProjector`, `texture_available` | optional hardware-texture backend |
|
|
122
|
+
| `shepp_logan_mm`, `rasterize` | 3D Shepp-Logan phantom in millimeter units |
|
|
123
|
+
|
|
124
|
+
Field names, array layouts and call signatures follow TIGRE. See
|
|
125
|
+
[docs/compatibility.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/compatibility.md) for what is and is not supported,
|
|
126
|
+
and where behavior differs.
|
|
127
|
+
|
|
128
|
+
## Limitations
|
|
129
|
+
|
|
130
|
+
- **Iterative and learned reconstruction are not included** — the package
|
|
131
|
+
provides the operators these methods are built from.
|
|
132
|
+
- **`Atb(backprojection_type="matched")` is an approximate adjoint.** Ray-driven
|
|
133
|
+
forward projection and voxel-driven backprojection are not exact transposes.
|
|
134
|
+
The measured discrepancy is 1.8e-4 relative on random test vectors; see
|
|
135
|
+
[docs/validation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/validation.md) for the method and for guidance if you
|
|
136
|
+
intend to use it in an iterative solver.
|
|
137
|
+
- **Half-fan offset-detector reconstruction (`dowang`) is not implemented**, so
|
|
138
|
+
transaxially truncated half-fan data is not handled.
|
|
139
|
+
- **MLX reductions reject arrays over 2^31-1 elements.** Very large volumes must
|
|
140
|
+
be reduced in chunks.
|
|
141
|
+
- **The hardware-texture backend is capped at 2048 elements per axis** by Metal.
|
|
142
|
+
- **`mlx` is pinned**, because the custom Metal kernels are validated against a
|
|
143
|
+
specific version.
|
|
144
|
+
|
|
145
|
+
## Validation
|
|
146
|
+
|
|
147
|
+
Correctness rests on three complementary layers: a float64 NumPy reference
|
|
148
|
+
implementation that the GPU kernels must agree with to approximately 1e-5
|
|
149
|
+
relative L2 in the tested configurations, an analytic ellipsoid line-integral
|
|
150
|
+
oracle sharing no code with that reference, and impulse-placement tests. Adjoint
|
|
151
|
+
identities and analytic reconstruction comparisons are also checked.
|
|
152
|
+
|
|
153
|
+
Volumes and projection stacks beyond 2^31-1 elements are handled by view and
|
|
154
|
+
z-slab splitting, validated at 2048³ against the analytic oracle.
|
|
155
|
+
|
|
156
|
+
Full detail and how to run everything: [docs/validation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/validation.md).
|
|
157
|
+
|
|
158
|
+
## Performance
|
|
159
|
+
|
|
160
|
+
Milliseconds per view, median of nine timed repetitions after a warm-up, on an
|
|
161
|
+
Apple M5 Max (40-core GPU, 128 GB, macOS 26.5.1, Python 3.14.6, MLX 0.32.0,
|
|
162
|
+
mains power, no other GPU load):
|
|
163
|
+
|
|
164
|
+
| problem | views | interpolated | Siddon | Atb (FDK) |
|
|
165
|
+
|---|---|---|---|---|
|
|
166
|
+
| 256³ ↔ 256² | 100 | 0.28 | 0.15 | 0.23 |
|
|
167
|
+
| 512³ ↔ 512² | 100 | 2.08 | 0.98 | 1.67 |
|
|
168
|
+
|
|
169
|
+
Observed scaling across machines is consistent with bandwidth-bound execution.
|
|
170
|
+
Kernel launch parameters are measured per device; run `harness/tune.py` on your
|
|
171
|
+
own hardware.
|
|
172
|
+
|
|
173
|
+
Methodology, run-to-run spread, Apple M1 figures, the large-volume measurement,
|
|
174
|
+
and tuning guidance: [docs/performance.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/performance.md).
|
|
175
|
+
|
|
176
|
+
## Documentation
|
|
177
|
+
|
|
178
|
+
- [docs/compatibility.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/compatibility.md) — supported API, and behavioral
|
|
179
|
+
differences from TIGRE
|
|
180
|
+
- [docs/validation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/validation.md) — how correctness is established, how
|
|
181
|
+
to run the suite, adjoint consistency
|
|
182
|
+
- [docs/performance.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/performance.md) — benchmark methodology and results
|
|
183
|
+
- [docs/implementation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/implementation.md) — precision model, kernels,
|
|
184
|
+
array splitting, tuning
|
|
185
|
+
- [CONTRIBUTING.md](https://github.com/martinlachaine/mlx-tomo/blob/main/CONTRIBUTING.md) — bug reports and development setup
|
|
186
|
+
- [CHANGELOG.md](https://github.com/martinlachaine/mlx-tomo/blob/main/CHANGELOG.md) — release history
|
|
187
|
+
|
|
188
|
+
## Development and validation
|
|
189
|
+
|
|
190
|
+
Generative AI tools assisted with implementation, refactoring, test scaffolding,
|
|
191
|
+
and documentation. The author defined the project's scope and numerical
|
|
192
|
+
requirements, reviewed the implementation, and is responsible for validation and
|
|
193
|
+
releases.
|
|
194
|
+
|
|
195
|
+
## License and citation
|
|
196
|
+
|
|
197
|
+
BSD-3-Clause; see [LICENSE](https://github.com/martinlachaine/mlx-tomo/blob/main/LICENSE). mlx-tomo adopts TIGRE's geometry
|
|
198
|
+
conventions and was validated against TIGRE; see [NOTICE](https://github.com/martinlachaine/mlx-tomo/blob/main/NOTICE) for
|
|
199
|
+
attribution and the TIGRE paper to cite, and [CITATION.cff](https://github.com/martinlachaine/mlx-tomo/blob/main/CITATION.cff) to
|
|
200
|
+
cite mlx-tomo itself.
|
mlx_tomo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# mlx-tomo
|
|
2
|
+
|
|
3
|
+
GPU-accelerated X-ray projection and backprojection for Apple silicon.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/martinlachaine/mlx-tomo/actions/workflows/ci.yml)
|
|
6
|
+
[](https://pypi.org/project/mlx-tomo/)
|
|
7
|
+
[](https://github.com/martinlachaine/mlx-tomo/blob/main/LICENSE)
|
|
8
|
+
[](https://github.com/martinlachaine/mlx-tomo/blob/main/pyproject.toml)
|
|
9
|
+
[](#requirements-and-installation)
|
|
10
|
+
|
|
11
|
+
mlx-tomo provides parallel-beam, fan-beam, and cone-beam forward and
|
|
12
|
+
backprojection using custom Metal kernels through MLX. It offers a
|
|
13
|
+
TIGRE-compatible Python interface for supported operations, making it easier to
|
|
14
|
+
adapt existing tomography workflows to Apple GPUs.
|
|
15
|
+
|
|
16
|
+
Host-side geometry calculations use float64, while GPU computation uses float32.
|
|
17
|
+
Numerical accuracy is validated against an independent float64 reference
|
|
18
|
+
implementation, analytic ellipsoid projections, and impulse-placement tests.
|
|
19
|
+
|
|
20
|
+
The package includes projection operators, geometry utilities, and analytic FDK
|
|
21
|
+
and FBP reconstruction. Iterative and learned reconstruction algorithms are
|
|
22
|
+
intentionally outside its current scope.
|
|
23
|
+
|
|
24
|
+
mlx-tomo is research software and has not been validated for clinical or
|
|
25
|
+
diagnostic use.
|
|
26
|
+
|
|
27
|
+
## Requirements and installation
|
|
28
|
+
|
|
29
|
+
Requires an Apple silicon Mac (Metal/MLX) and Python 3.11 or newer.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install mlx-tomo
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or install a tagged release from GitHub:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install "git+https://github.com/martinlachaine/mlx-tomo.git@v0.1.0"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`mlx` is pinned to a validated version; `numpy` has a lower bound. Check the
|
|
42
|
+
install with:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import numpy as np
|
|
46
|
+
import mlx_tomo
|
|
47
|
+
|
|
48
|
+
geo = mlx_tomo.geometry_default(high_resolution=False)
|
|
49
|
+
proj = mlx_tomo.Ax(np.ones(tuple(geo.nVoxel), np.float32), geo, np.array([0.0]))
|
|
50
|
+
print(mlx_tomo.__version__, proj.shape)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Development installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git clone https://github.com/martinlachaine/mlx-tomo && cd mlx-tomo
|
|
57
|
+
uv venv --python 3.13 .venv
|
|
58
|
+
uv pip install -p .venv/bin/python -e ".[dev]"
|
|
59
|
+
cd texture_bridge && ./build.sh && cd .. # optional texture backend
|
|
60
|
+
.venv/bin/python harness/run_tests.py # full correctness suite
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quickstart
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import numpy as np
|
|
67
|
+
import mlx_tomo as tigre
|
|
68
|
+
|
|
69
|
+
geo = tigre.geometry_default(high_resolution=False) # 64^3 volume, 128^2 detector
|
|
70
|
+
vol = tigre.rasterize(geo, tigre.shepp_logan_mm(scale_mm=100.0))
|
|
71
|
+
|
|
72
|
+
angles = np.linspace(0, 2 * np.pi, 360, endpoint=False)
|
|
73
|
+
proj = tigre.Ax(vol, geo, angles, projection_type="interpolated")
|
|
74
|
+
rec = tigre.FDK(proj, geo, angles)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`proj` is `(n_angles, nDetector[0], nDetector[1])` float32 line integrals in
|
|
78
|
+
millimeter units; `rec` matches `geo.nVoxel` as `[z, y, x]`.
|
|
79
|
+
|
|
80
|
+
`examples/quickstart.py` runs cone and parallel projections and both
|
|
81
|
+
reconstructions end to end.
|
|
82
|
+
|
|
83
|
+
## API
|
|
84
|
+
|
|
85
|
+
| | |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `geometry(mode=...)`, `geometry_default()` | geometry container |
|
|
88
|
+
| `Ax(img, geo, angles, projection_type)` | forward projection; `"interpolated"` or `"Siddon"` |
|
|
89
|
+
| `Atb(proj, geo, angles, backprojection_type)` | backprojection; `"FDK"` or `"matched"` |
|
|
90
|
+
| `Ax_rays`, `rays_from_geometry`, `affine_rays` | projection along user-supplied rays |
|
|
91
|
+
| `FDK`, `FBP`, `filtering` | analytic reconstruction; ramp filters, windows, Parker weights |
|
|
92
|
+
| `TextureProjector`, `texture_available` | optional hardware-texture backend |
|
|
93
|
+
| `shepp_logan_mm`, `rasterize` | 3D Shepp-Logan phantom in millimeter units |
|
|
94
|
+
|
|
95
|
+
Field names, array layouts and call signatures follow TIGRE. See
|
|
96
|
+
[docs/compatibility.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/compatibility.md) for what is and is not supported,
|
|
97
|
+
and where behavior differs.
|
|
98
|
+
|
|
99
|
+
## Limitations
|
|
100
|
+
|
|
101
|
+
- **Iterative and learned reconstruction are not included** — the package
|
|
102
|
+
provides the operators these methods are built from.
|
|
103
|
+
- **`Atb(backprojection_type="matched")` is an approximate adjoint.** Ray-driven
|
|
104
|
+
forward projection and voxel-driven backprojection are not exact transposes.
|
|
105
|
+
The measured discrepancy is 1.8e-4 relative on random test vectors; see
|
|
106
|
+
[docs/validation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/validation.md) for the method and for guidance if you
|
|
107
|
+
intend to use it in an iterative solver.
|
|
108
|
+
- **Half-fan offset-detector reconstruction (`dowang`) is not implemented**, so
|
|
109
|
+
transaxially truncated half-fan data is not handled.
|
|
110
|
+
- **MLX reductions reject arrays over 2^31-1 elements.** Very large volumes must
|
|
111
|
+
be reduced in chunks.
|
|
112
|
+
- **The hardware-texture backend is capped at 2048 elements per axis** by Metal.
|
|
113
|
+
- **`mlx` is pinned**, because the custom Metal kernels are validated against a
|
|
114
|
+
specific version.
|
|
115
|
+
|
|
116
|
+
## Validation
|
|
117
|
+
|
|
118
|
+
Correctness rests on three complementary layers: a float64 NumPy reference
|
|
119
|
+
implementation that the GPU kernels must agree with to approximately 1e-5
|
|
120
|
+
relative L2 in the tested configurations, an analytic ellipsoid line-integral
|
|
121
|
+
oracle sharing no code with that reference, and impulse-placement tests. Adjoint
|
|
122
|
+
identities and analytic reconstruction comparisons are also checked.
|
|
123
|
+
|
|
124
|
+
Volumes and projection stacks beyond 2^31-1 elements are handled by view and
|
|
125
|
+
z-slab splitting, validated at 2048³ against the analytic oracle.
|
|
126
|
+
|
|
127
|
+
Full detail and how to run everything: [docs/validation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/validation.md).
|
|
128
|
+
|
|
129
|
+
## Performance
|
|
130
|
+
|
|
131
|
+
Milliseconds per view, median of nine timed repetitions after a warm-up, on an
|
|
132
|
+
Apple M5 Max (40-core GPU, 128 GB, macOS 26.5.1, Python 3.14.6, MLX 0.32.0,
|
|
133
|
+
mains power, no other GPU load):
|
|
134
|
+
|
|
135
|
+
| problem | views | interpolated | Siddon | Atb (FDK) |
|
|
136
|
+
|---|---|---|---|---|
|
|
137
|
+
| 256³ ↔ 256² | 100 | 0.28 | 0.15 | 0.23 |
|
|
138
|
+
| 512³ ↔ 512² | 100 | 2.08 | 0.98 | 1.67 |
|
|
139
|
+
|
|
140
|
+
Observed scaling across machines is consistent with bandwidth-bound execution.
|
|
141
|
+
Kernel launch parameters are measured per device; run `harness/tune.py` on your
|
|
142
|
+
own hardware.
|
|
143
|
+
|
|
144
|
+
Methodology, run-to-run spread, Apple M1 figures, the large-volume measurement,
|
|
145
|
+
and tuning guidance: [docs/performance.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/performance.md).
|
|
146
|
+
|
|
147
|
+
## Documentation
|
|
148
|
+
|
|
149
|
+
- [docs/compatibility.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/compatibility.md) — supported API, and behavioral
|
|
150
|
+
differences from TIGRE
|
|
151
|
+
- [docs/validation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/validation.md) — how correctness is established, how
|
|
152
|
+
to run the suite, adjoint consistency
|
|
153
|
+
- [docs/performance.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/performance.md) — benchmark methodology and results
|
|
154
|
+
- [docs/implementation.md](https://github.com/martinlachaine/mlx-tomo/blob/main/docs/implementation.md) — precision model, kernels,
|
|
155
|
+
array splitting, tuning
|
|
156
|
+
- [CONTRIBUTING.md](https://github.com/martinlachaine/mlx-tomo/blob/main/CONTRIBUTING.md) — bug reports and development setup
|
|
157
|
+
- [CHANGELOG.md](https://github.com/martinlachaine/mlx-tomo/blob/main/CHANGELOG.md) — release history
|
|
158
|
+
|
|
159
|
+
## Development and validation
|
|
160
|
+
|
|
161
|
+
Generative AI tools assisted with implementation, refactoring, test scaffolding,
|
|
162
|
+
and documentation. The author defined the project's scope and numerical
|
|
163
|
+
requirements, reviewed the implementation, and is responsible for validation and
|
|
164
|
+
releases.
|
|
165
|
+
|
|
166
|
+
## License and citation
|
|
167
|
+
|
|
168
|
+
BSD-3-Clause; see [LICENSE](https://github.com/martinlachaine/mlx-tomo/blob/main/LICENSE). mlx-tomo adopts TIGRE's geometry
|
|
169
|
+
conventions and was validated against TIGRE; see [NOTICE](https://github.com/martinlachaine/mlx-tomo/blob/main/NOTICE) for
|
|
170
|
+
attribution and the TIGRE paper to cite, and [CITATION.cff](https://github.com/martinlachaine/mlx-tomo/blob/main/CITATION.cff) to
|
|
171
|
+
cite mlx-tomo itself.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""mlx-tomo: parallel-, fan- and cone-beam projectors on Apple GPUs (Metal/MLX).
|
|
2
|
+
|
|
3
|
+
TIGRE-compatible Python interface for supported operations: ``import mlx_tomo as
|
|
4
|
+
tigre`` then use ``tigre.Ax(img, geo, angles, projection_type)`` with a
|
|
5
|
+
``tigre.geometry()`` object. See https://github.com/martinlachaine/mlx-tomo/blob/main/docs/compatibility.md for what is supported and
|
|
6
|
+
where behavior differs.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .geometry import Geometry, ParallelGeo, geometry, geometry_default
|
|
10
|
+
|
|
11
|
+
__version__ = "0.1.0"
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"Geometry", "ParallelGeo", "geometry", "geometry_default",
|
|
15
|
+
"Ax", "Atb", "Ax_rays", "rays_from_geometry", "affine_rays",
|
|
16
|
+
"FDK", "FBP", "fdk", "fbp", "filtering",
|
|
17
|
+
"TextureProjector", "texture_available",
|
|
18
|
+
"shepp_logan_mm", "rasterize", "__version__",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def __getattr__(name): # PEP 562: lazy re-exports (real class, not a wrapper)
|
|
23
|
+
if name == "TextureProjector":
|
|
24
|
+
from .texture import TextureProjector
|
|
25
|
+
return TextureProjector
|
|
26
|
+
if name == "texture_available":
|
|
27
|
+
from .texture import available
|
|
28
|
+
return available
|
|
29
|
+
if name in ("Ax_rays", "rays_from_geometry", "affine_rays"):
|
|
30
|
+
from . import rays
|
|
31
|
+
return getattr(rays, name)
|
|
32
|
+
if name in ("shepp_logan_mm", "rasterize", "region_masks",
|
|
33
|
+
"ground_truth_values"):
|
|
34
|
+
from . import phantom3d
|
|
35
|
+
return getattr(phantom3d, name)
|
|
36
|
+
if name in ("FDK", "FBP", "fdk", "fbp"):
|
|
37
|
+
from . import algorithms
|
|
38
|
+
return getattr(algorithms, name)
|
|
39
|
+
raise AttributeError(f"module 'mlx_tomo' has no attribute {name!r}")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Bound eagerly: the import system would otherwise set the package
|
|
43
|
+
# attribute to the SUBMODULE mlx_tomo.filtering the first time anything
|
|
44
|
+
# imports it, shadowing the function the public API promises.
|
|
45
|
+
from .filtering import filtering as filtering # noqa: E402
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def Ax(img, geo, angles, projection_type="Siddon", **kwargs):
|
|
49
|
+
from .api import Ax as _Ax
|
|
50
|
+
return _Ax(img, geo, angles, projection_type=projection_type, **kwargs)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def Atb(proj, geo, angles, backprojection_type="FDK", **kwargs):
|
|
54
|
+
from .api import Atb as _Atb
|
|
55
|
+
return _Atb(proj, geo, angles, backprojection_type=backprojection_type,
|
|
56
|
+
**kwargs)
|