Skip to content

Round a pulse the same whichever terms the kernel was compiled for - #30

Merged
mcencini merged 1 commit into
mainfrom
epg-kernel-gate-exact
Oct 6, 2026
Merged

mcencini merged 1 commit into
mainfrom
epg-kernel-gate-exact

Conversation

@mcencini

@mcencini mcencini commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

On a card, tests/sequence/test_feature_gates.py::test_the_forward_answer_does_not_depend_on_the_gate fails on main for all six cases since #29: the forward kernel compiled for the terms a tissue declares answers about one ulp (1.3e-7) away from the kernel compiled with every term, on the same input. The CI runners have no GPU, so #29's checks did not reach it.

Cause

#29 replaced library calls with arithmetic: a Cody–Waite reduction and Cephes polynomials for the flip angle, the event phase turned by the transmit phase through products, and the double angle from those products. Those sums of products feed _rotate_flip_phase. The compiler contracts a*b + c*d into a fused multiply-add, and which product it fuses depends on the surrounding code. A variant where off_axis or transmit is off folds b1_cos = 1, b1_sin = 0 and atom_b1 = 1 into constants, and so contracts differently. With TRITON_DEFAULT_FP_FUSION=0, every gate gives the same bits.

Change

The reduction, both polynomials, the transmit-phase turn, the double angle and every term of _rotate_flip_phase are explicit tl.fma in a fixed order. Nothing is left for the compiler to contract, so every variant rounds the same way.

Checks (RTX 4060 Laptop, Triton 3.7.1)

  • pytest tests/sequence: 1013 passed, 1 skipped (on main: 6 failed, all in test_feature_gates).
  • Each gate added alone to the bare tissue (B0, B1_PHASE, FLOW, DIFFUSION, B1, M0, INVERSION) and every term together: bit-identical to the bare kernel.
  • An RF-spoiled FLASH, 1000 shots, 6000 voxels with an off-resonance map, best of 7: 1.94–1.96 s on main, 2.00–2.03 s here. Turning fusion off for the whole kernel instead gives 2.27 s.

🤖 Generated with Claude Code

The pulse's sine and cosine, its phase turned by the transmit field's, its
double angle and the rotation of the states are written as fused
multiply-adds in a fixed order. Left to the compiler, each kernel variant
contracted them its own way, and a tissue declaring fewer terms got an
answer one ulp away from the full kernel's on the same input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mcencini
mcencini merged commit c255ae9 into main Oct 6, 2026
22 checks passed
@mcencini
mcencini deleted the epg-kernel-gate-exact branch October 6, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant