Repository navigation
DictionaryMatcher: exhaustive best-atom match in one CUDA kernel - #55
Merged
Merged
Conversation
Without groups or a lattice, top_k=1, real float32 atoms and up to 16 contrasts, the match of float32 or complex64 signals on a card runs as one kernel (_match.cu, bound in _gpu as match_best): each thread holds four signals in registers, atoms are staged in shared memory and read as broadcasts, and only the best atom and its score are kept. The voxels-by-atoms score matrix is never stored, and there is one launch per call instead of a product, an absolute value and a reduction per chunk of atoms (or, with groups, a few launches and a sync per group). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MFB6QLjhTxFMFDEzathbEm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
The exhaustive match (no groups, no lattice) now runs on a card as a single kernel (
src/blochsim/_match.cu, bound in_gpuasmatch_best). It applies withtop_k=1, real float32 atoms, up to 16 contrasts, and float32 or complex64 signals. Each thread holds four signals in registers, the atoms are staged in shared memory and read as broadcasts, and only the best atom and its score are kept. Any case outside those conditions is matched in tensors as before. Fast group matching (groups=) and the coarse lattice are unchanged.Why
On a card, matching in tensors writes the voxels-by-atoms score matrix and then reads it back for the absolute value and the reduction, once per chunk of atoms. Group matching saves arithmetic but costs a few launches and a sync per group. In MRI2Qmap's 256³ joint projection (7 contrasts, about 21k atoms, 100 groups), that is about 6,400 small launches per call. They are cheap on an A40, but under WSL on an RTX 4060 laptop the projection was 7x the A40's time, well beyond the compute ratio. Matching every voxel against every atom is about 5 TFLOP, so a kernel that never stores the scores searches every atom faster than group matching prunes them.
Validation
On an A40, with blochsim-cuda13 built for 80/86/89:
tests/estimators/test_dictionary.py+test_grouped.py: 36 passed, 1 failed.test_the_card_kernel_finds_the_tensor_matchcases ran and passed. They cover real and complex signals at 3, 7 and 16 contrasts, plus 17 contrasts, which falls back to tensors. In each case the indices are identical to the tensor path's, and the scores and scales agree to 1e-5.test_without_refinement_the_coarse_lattice_alone_is_searched, fails identically at the parent commit 339d0be, so it predates this change.Documentation impact
CHANGELOG entry under Unreleased/Added. The public API is unchanged: an existing exhaustive
DictionaryMatchersimply runs faster on a card.Checklist
ruff formatandruff checkare clean.correlate(|<s, d>|, hypot for complex signals against real atoms), pinned against the tensor path.🤖 Generated with Claude Code
https://claude.ai/code/session_01MFB6QLjhTxFMFDEzathbEm