diffct 1.2.9__tar.gz → 1.2.11__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 (56) hide show
  1. diffct-1.2.11/CHANGELOG.md +225 -0
  2. {diffct-1.2.9 → diffct-1.2.11}/PKG-INFO +1 -1
  3. {diffct-1.2.9 → diffct-1.2.11}/diffct/__init__.py +17 -16
  4. {diffct-1.2.9 → diffct-1.2.11}/diffct/differentiable.py +652 -199
  5. {diffct-1.2.9 → diffct-1.2.11}/docs/Makefile +20 -20
  6. diffct-1.2.11/docs/source/api.rst +220 -0
  7. diffct-1.2.11/docs/source/fbp_fan_example.rst +158 -0
  8. diffct-1.2.11/docs/source/fbp_parallel_example.rst +117 -0
  9. diffct-1.2.11/docs/source/fdk_cone_example.rst +184 -0
  10. diffct-1.2.11/examples/fbp_fan.py +284 -0
  11. diffct-1.2.11/examples/fbp_parallel.py +225 -0
  12. diffct-1.2.11/examples/fdk_cone.py +408 -0
  13. {diffct-1.2.9 → diffct-1.2.11}/pyproject.toml +1 -1
  14. diffct-1.2.11/pytest.ini +14 -0
  15. diffct-1.2.11/tests/benchmarks/README.md +60 -0
  16. diffct-1.2.11/tests/benchmarks/__init__.py +0 -0
  17. diffct-1.2.11/tests/benchmarks/_common.py +62 -0
  18. diffct-1.2.11/tests/benchmarks/test_bench_cone.py +145 -0
  19. diffct-1.2.11/tests/benchmarks/test_bench_fan.py +127 -0
  20. diffct-1.2.11/tests/benchmarks/test_bench_parallel.py +115 -0
  21. diffct-1.2.11/tests/test_adjoint_inner_product.py +155 -0
  22. diffct-1.2.11/tests/test_cone_projector_autograd.py +91 -0
  23. {diffct-1.2.9 → diffct-1.2.11}/tests/test_cuda_smoke.py +3 -0
  24. diffct-1.2.11/tests/test_fbp_fan_accuracy.py +147 -0
  25. diffct-1.2.11/tests/test_fbp_fan_offsets.py +162 -0
  26. diffct-1.2.11/tests/test_fbp_parallel_accuracy.py +164 -0
  27. diffct-1.2.11/tests/test_fdk_cone_accuracy.py +197 -0
  28. diffct-1.2.11/tests/test_fdk_cone_offsets.py +210 -0
  29. diffct-1.2.11/tests/test_gradcheck.py +136 -0
  30. diffct-1.2.11/tests/test_ramp_filter_windows.py +217 -0
  31. {diffct-1.2.9 → diffct-1.2.11}/tests/test_weights.py +61 -61
  32. diffct-1.2.9/docs/source/api.rst +0 -86
  33. diffct-1.2.9/docs/source/fbp_fan_example.rst +0 -84
  34. diffct-1.2.9/docs/source/fbp_parallel_example.rst +0 -69
  35. diffct-1.2.9/docs/source/fdk_cone_example.rst +0 -99
  36. diffct-1.2.9/examples/fbp_fan.py +0 -132
  37. diffct-1.2.9/examples/fbp_parallel.py +0 -96
  38. diffct-1.2.9/examples/fdk_cone.py +0 -163
  39. diffct-1.2.9/pytest.ini +0 -3
  40. {diffct-1.2.9 → diffct-1.2.11}/.github/workflows/docs.yml +0 -0
  41. {diffct-1.2.9 → diffct-1.2.11}/.github/workflows/release.yml +0 -0
  42. {diffct-1.2.9 → diffct-1.2.11}/.gitignore +0 -0
  43. {diffct-1.2.9 → diffct-1.2.11}/LICENSE +0 -0
  44. {diffct-1.2.9 → diffct-1.2.11}/README.md +0 -0
  45. {diffct-1.2.9 → diffct-1.2.11}/docs/source/_static/.gitkeep +0 -0
  46. {diffct-1.2.9 → diffct-1.2.11}/docs/source/conf.py +0 -0
  47. {diffct-1.2.9 → diffct-1.2.11}/docs/source/examples.rst +0 -0
  48. {diffct-1.2.9 → diffct-1.2.11}/docs/source/getting_started.rst +0 -0
  49. {diffct-1.2.9 → diffct-1.2.11}/docs/source/index.rst +0 -0
  50. {diffct-1.2.9 → diffct-1.2.11}/docs/source/iterative_reco_cone_example.rst +0 -0
  51. {diffct-1.2.9 → diffct-1.2.11}/docs/source/iterative_reco_fan_example.rst +0 -0
  52. {diffct-1.2.9 → diffct-1.2.11}/docs/source/iterative_reco_parallel_example.rst +0 -0
  53. {diffct-1.2.9 → diffct-1.2.11}/examples/iterative_reco_cone.py +0 -0
  54. {diffct-1.2.9 → diffct-1.2.11}/examples/iterative_reco_fan.py +0 -0
  55. {diffct-1.2.9 → diffct-1.2.11}/examples/iterative_reco_parallel.py +0 -0
  56. {diffct-1.2.9 → diffct-1.2.11}/requirements.txt +0 -0
@@ -0,0 +1,225 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.2.11] - 2026-04-14
11
+
12
+ ### Added
13
+ - **Parker short-scan demos** in `examples/fdk_cone.py` and `examples/fbp_fan.py`.
14
+ Both examples now expose an `apply_parker` switch that not only multiplies
15
+ by `parker_weights` but also samples angles on the minimal short-scan range
16
+ `pi + 2*gamma_max`, where `gamma_max` is computed from the detector half-width
17
+ and `sdd`. (Before this change the `apply_parker` flag in `fbp_fan.py` was
18
+ silently a no-op because the angular range stayed at `2*pi`.)
19
+ - **`tests/test_gradcheck.py`** — `torch.autograd.gradcheck` coverage for
20
+ `ParallelProjectorFunction`, `FanProjectorFunction`, and `ConeProjectorFunction`.
21
+ Compares the analytical backward Jacobian to a finite-difference numerical
22
+ Jacobian over small inputs with float32-calibrated tolerances. Strongest
23
+ autograd-correctness guard beyond the existing inner-product adjoint tests.
24
+ - **`tests/test_ramp_filter_windows.py`** — 27 parametrised tests covering every
25
+ `ramp_filter_1d` window option (`None`/`"ram-lak"`, `"hann"`, `"hanning"`,
26
+ `"hamming"`, `"cosine"`, `"shepp-logan"`) at three layers: direct `_ramp_window`
27
+ helper (DC gain, Nyquist value, monotonicity), full `ramp_filter_1d` end-to-end
28
+ (shape, DC annihilation, pad correctness, rfft vs complex-fft parity,
29
+ `sample_spacing` scaling), and a high-frequency attenuation sanity check on a
30
+ step input.
31
+ - **`CHANGELOG.md`** — new Keep-a-Changelog file at the repo root.
32
+ - **`tests/benchmarks/`** — opt-in `pytest-benchmark` suite covering every CUDA
33
+ kernel in the library (forward projector, pure-adjoint backprojector, and
34
+ analytical FBP/FDK pipeline) across three sizes for each of the three
35
+ geometries. 27 benchmarks total. Excluded from the default `pytest tests/`
36
+ run via `--ignore=tests/benchmarks` in `pytest.ini` so the normal test suite
37
+ stays fast; run explicitly with `pytest tests/benchmarks/ --benchmark-only`.
38
+ Enables before/after perf comparisons via `--benchmark-save=` /
39
+ `--benchmark-compare=`.
40
+
41
+ ### Changed
42
+ - **`_cone_3d_fdk_backproject_kernel`** memory-access layout. The kernel now
43
+ unpacks `cuda.grid(3)` as `(iz, iy, ix)` instead of `(ix, iy, iz)`, and
44
+ `cone_weighted_backproject` launches the grid as `_grid_3d(D, H, W)` instead
45
+ of `_grid_3d(W, H, D)`. This makes `iz` warp-adjacent, which matches the
46
+ innermost stride-1 axis of the WHD output buffer, so the final `d_vol` write
47
+ becomes coalesced. Measured speedup on a 64^3–160^3 sweep: 1.0x–1.14x,
48
+ within run-to-run noise (the kernel is read-bound on the sinogram bilinear
49
+ samples, not write-bound, so L2 absorbed the old uncoalesced writes). The
50
+ fix is kept as the right default and future-proofs the kernel against
51
+ edits that shift work toward the write path. Matching coalescing comments
52
+ were added to the 2D `_parallel_2d_fbp_backproject_kernel` and
53
+ `_fan_2d_fbp_backproject_kernel` kernels, which were already coalesced
54
+ (their first grid index is also warp-adjacent and matches the `Nx` innermost
55
+ axis of their `(Ny, Nx)` output buffers).
56
+
57
+ ### Notes
58
+ - No public-API changes. Pure-adjoint kernels and autograd Function classes
59
+ are untouched, so the autograd and iterative-reconstruction paths are
60
+ byte-for-byte equivalent to 1.2.10.
61
+
62
+ ## [1.2.10] - 2026-04-14
63
+
64
+ This release is a correctness overhaul of every analytical reconstruction path
65
+ (parallel / fan / cone) **and** of the autograd adjoint path shared by the
66
+ iterative examples. It also ships a unified architecture where each geometry
67
+ has its own dedicated voxel-driven FBP/FDK gather kernel, separate from the
68
+ pure Siddon adjoint used by autograd.
69
+
70
+ ### Fixed
71
+
72
+ #### Analytical FBP / FDK amplitude bugs
73
+
74
+ Prior to this release, all three analytical reconstruction examples produced
75
+ results that were off by large constant factors:
76
+
77
+ | Example | Pre-fix reco range | Post-fix reco range | MSE improvement |
78
+ |---|---|---|---|
79
+ | `fbp_parallel.py` | [0, 6.52] | [−0.02, 1.01] | ~580× |
80
+ | `fbp_fan.py` | [0, 6.33] | [−0.08, 1.01] | ~900× |
81
+ | `fdk_cone.py` | [0, 10.08] | [−0.08, 1.00] | ~600× |
82
+
83
+ Root causes:
84
+ - Cone and fan used `(sdd/U)^2` with `U = sdd + x·sin − y·cos` instead of
85
+ the correct FDK weight `(sid/U)^2` with `U = sid + x·sin − y·cos`.
86
+ - All three geometries were missing the `1/(2π)` Fourier-convention
87
+ constant from the FBP/FDK reconstruction formula.
88
+ - Cone and fan used a Siddon ray-driven scatter for the analytical path,
89
+ which is neither a true adjoint nor a classical FBP/FDK gather.
90
+
91
+ #### Autograd adjoint bug (cone + fan)
92
+
93
+ `ConeProjectorFunction.backward`, `ConeBackprojectorFunction.forward`,
94
+ `FanProjectorFunction.backward` and `FanBackprojectorFunction.forward`
95
+ were all passing `distance_weight=1.0` to the shared Siddon backward
96
+ kernel. This meant the autograd backward was **not the true adjoint** `P^T`
97
+ of the forward projector — it had a `(sdd/U)^2` per-voxel factor baked in,
98
+ biasing the gradient by ~2–3× depending on voxel position. Any iterative
99
+ reconstruction that relied on autograd (including `iterative_reco_cone.py`
100
+ and `iterative_reco_fan.py`) was running on a biased gradient flow.
101
+
102
+ Parallel beam was unaffected (its backward kernel had no `distance_weight`
103
+ parameter to begin with).
104
+
105
+ This release removes the `distance_weight` parameter from both
106
+ `_cone_3d_backward_kernel` and `_fan_2d_backward_kernel` entirely, so the
107
+ dead code path cannot be accidentally reintroduced, and fixes the four
108
+ autograd call sites to use the pure adjoint.
109
+
110
+ ### Added
111
+
112
+ #### Voxel-driven gather kernels for every geometry
113
+
114
+ Three new CUDA kernels, all under a dedicated `fastmath=False` decorator
115
+ for FDK-grade accuracy:
116
+
117
+ - `_parallel_2d_fbp_backproject_kernel` — no distance weighting (no source).
118
+ - `_fan_2d_fbp_backproject_kernel` — `(sid/U)^2` + linear detector interp.
119
+ - `_cone_3d_fdk_backproject_kernel` — `(sid/U)^2` + bilinear detector interp.
120
+
121
+ Each kernel is voxel-driven: one thread per output pixel/voxel, loops over
122
+ views, computes the projected detector coordinate, interpolates the filtered
123
+ sinogram, weights and accumulates.
124
+
125
+ #### `parallel_weighted_backproject` (new public helper)
126
+
127
+ Mirrors `fan_weighted_backproject` and `cone_weighted_backproject`. Applies
128
+ the `1/(2π)` Fourier-convention constant so a unit-density disk reconstructs
129
+ to amplitude 1. Exported from `diffct`.
130
+
131
+ #### `ramp_filter_1d` — new backward-compatible kwargs
132
+
133
+ - `sample_spacing` (default `1.0`): physical detector cell pitch. Output is
134
+ rescaled by `1/sample_spacing` for physical-unit correctness.
135
+ - `pad_factor` (default `1`): zero-pad to `pad_factor * N` before the FFT to
136
+ suppress circular-convolution wrap-around. `2` is recommended for FBP/FDK.
137
+ - `window` (default `None`): frequency-domain apodization. Options: `None` /
138
+ `"ram-lak"`, `"hann"`, `"hamming"`, `"cosine"`, `"shepp-logan"`.
139
+ - `use_rfft` (default `True`): faster real-FFT path for real-valued inputs.
140
+
141
+ Existing `ramp_filter_1d(sino, dim=1)` calls keep working unchanged.
142
+
143
+ #### Analytical FBP / FDK scale factors
144
+
145
+ Each analytical helper now applies the correct analytical constant
146
+ automatically so reconstructions are already amplitude-calibrated:
147
+
148
+ - `parallel_weighted_backproject`: `1 / (2π)`.
149
+ - `fan_weighted_backproject`: `sdd / (2π · sid)`.
150
+ - `cone_weighted_backproject`: `sdd / (2π · sid)`.
151
+
152
+ ### Tests
153
+
154
+ Test suite expanded from 6 to **27 tests**:
155
+
156
+ - `tests/test_adjoint_inner_product.py` — the definitive check. For random `x`
157
+ and `y`, asserts `⟨A x, y⟩ = ⟨x, A^T y⟩` for parallel, fan and cone autograd
158
+ pairs. Permanently guards against any regression that would reintroduce the
159
+ `distance_weight=1.0` bug.
160
+ - `tests/test_fdk_cone_accuracy.py` — 128³ Shepp-Logan RMSE / amplitude bounds.
161
+ - `tests/test_fdk_cone_offsets.py` — detector, center and combined offsets with
162
+ amplitude assertions.
163
+ - `tests/test_cone_projector_autograd.py` — gradient finiteness and non-zero
164
+ sanity.
165
+ - `tests/test_fbp_fan_accuracy.py` — 256×256 Shepp-Logan RMSE.
166
+ - `tests/test_fbp_fan_offsets.py` — three offset configurations.
167
+ - `tests/test_fbp_parallel_accuracy.py` — parallel FBP RMSE + offset.
168
+
169
+ ### Examples
170
+
171
+ `examples/fdk_cone.py`, `examples/fbp_fan.py` and `examples/fbp_parallel.py`
172
+ have been rewritten with a consistent 8-step layout and detailed inline
173
+ comments documenting every geometry variable (what it is, units, typical
174
+ values, available options). Each example prints raw MSE, clamped MSE, and the
175
+ reconstruction / phantom data ranges.
176
+
177
+ The iterative reconstruction examples (`iterative_reco_parallel.py`,
178
+ `iterative_reco_fan.py`, `iterative_reco_cone.py`) are unchanged — they
179
+ silently benefit from the fixed autograd adjoint.
180
+
181
+ ### Documentation
182
+
183
+ - `docs/source/api.rst`: adds autofunction entries for
184
+ `parallel_weighted_backproject`, documents the new `ramp_filter_1d`
185
+ options, and adds an "Analytical FBP / FDK architecture" section
186
+ explaining the scale-factor derivation.
187
+ - `docs/source/fdk_cone_example.rst`: formula updated to reflect the
188
+ voxel-gather kernel and `(sid/U)^2` weight.
189
+ - `docs/source/fbp_fan_example.rst` and `fbp_parallel_example.rst`: completely
190
+ rewritten to reference the new analytical helpers and fix a sign-convention
191
+ inconsistency in the math section.
192
+
193
+ ### Compatibility
194
+
195
+ This release is source-compatible with 1.2.9 for every public entry point. The
196
+ `distance_weight` parameter was internal and is removed from the private
197
+ backward kernels; no public API touched that argument.
198
+
199
+ ## [1.2.9] - 2026-02-14
200
+
201
+ Restored `main` to the state of 1.2.9 by reverting an accidental merge.
202
+ See [GitHub release v1.2.9](https://github.com/sypsyp97/diffct/releases/tag/v1.2.9).
203
+
204
+ ## [1.2.8] - 2026-02-14
205
+
206
+ See [GitHub release v1.2.8](https://github.com/sypsyp97/diffct/releases/tag/v1.2.8)
207
+ and the commit history for details.
208
+
209
+ ## [1.2.7] - 2025-08-05
210
+
211
+ See [GitHub release v1.2.7](https://github.com/sypsyp97/diffct/releases/tag/v1.2.7).
212
+
213
+ ## Earlier versions
214
+
215
+ Releases 1.2.0 through 1.2.6 and the 1.1.x / 1.0.x lines are tracked on
216
+ [GitHub releases](https://github.com/sypsyp97/diffct/releases). This CHANGELOG
217
+ was introduced in 1.2.10 and does not back-fill detailed notes for earlier
218
+ versions beyond pointers to the GitHub release pages.
219
+
220
+ [Unreleased]: https://github.com/sypsyp97/diffct/compare/v1.2.11...HEAD
221
+ [1.2.11]: https://github.com/sypsyp97/diffct/releases/tag/v1.2.11
222
+ [1.2.10]: https://github.com/sypsyp97/diffct/releases/tag/v1.2.10
223
+ [1.2.9]: https://github.com/sypsyp97/diffct/releases/tag/v1.2.9
224
+ [1.2.8]: https://github.com/sypsyp97/diffct/releases/tag/v1.2.8
225
+ [1.2.7]: https://github.com/sypsyp97/diffct/releases/tag/v1.2.7
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffct
3
- Version: 1.2.9
3
+ Version: 1.2.11
4
4
  Summary: A CUDA-based library for computed tomography (CT) projection and reconstruction with differentiable operators
5
5
  Project-URL: Homepage, https://github.com/sypsyp97/diffct
6
6
  Author-email: Yipeng Sun <yipeng.sun@fau.de>
@@ -1,17 +1,18 @@
1
1
  # diffct/__init__.py
2
- from .differentiable import (
3
- ParallelProjectorFunction,
4
- ParallelBackprojectorFunction,
5
- FanProjectorFunction,
6
- FanBackprojectorFunction,
7
- ConeProjectorFunction,
8
- ConeBackprojectorFunction,
9
- detector_coordinates_1d,
10
- angular_integration_weights,
11
- fan_cosine_weights,
12
- cone_cosine_weights,
13
- parker_weights,
14
- ramp_filter_1d,
15
- fan_weighted_backproject,
16
- cone_weighted_backproject,
17
- )
2
+ from .differentiable import (
3
+ ParallelProjectorFunction,
4
+ ParallelBackprojectorFunction,
5
+ FanProjectorFunction,
6
+ FanBackprojectorFunction,
7
+ ConeProjectorFunction,
8
+ ConeBackprojectorFunction,
9
+ detector_coordinates_1d,
10
+ angular_integration_weights,
11
+ fan_cosine_weights,
12
+ cone_cosine_weights,
13
+ parker_weights,
14
+ ramp_filter_1d,
15
+ parallel_weighted_backproject,
16
+ fan_weighted_backproject,
17
+ cone_weighted_backproject,
18
+ )