Two things in the indexing path, one of them a reproducibility hole.
XtalOptimizerData bounds a solve by iterations when it is told to and by WALL-CLOCK SECONDS when it
is not, and its own header says why that matters: the same image refines to a different answer on a
busier machine. The per-image refinement sets the iteration bound for exactly that reason. The
rotation indexer never did, so its candidate-cell refinement ran under a one-second wall clock -
three stages a candidate, up to eight candidates a scheme, twice a run. A run that has just been
made reproducible from its prediction order to its accumulators was still free to pick a different
lattice because the machine was loaded. It now takes the iteration bound offline and keeps the
wall-clock one for a live acquisition, whose budget is real, which is the same split the per-image
path already makes.
The residual itself rotated the same axis three times over. It applies one orientation to three
reciprocal-lattice vectors, and ceres::AngleAxisRotatePoint recomputes the angle, its sine, its
cosine and the normalised axis on each call - and it does not inline at this optimisation level, so
the compiler cannot notice. On a seventeen-parameter Jet each of those is a full dual-number
evaluation. Computing the rotation once and applying it three times removes two hypots, two sines,
two cosines, two divisions and six multiplies from every evaluation, which is about half the libm
calls in it; hoisting a constant member's sine and cosine out of the same function takes two more.
It runs everywhere the residual does - the indexer, the per-image refinement and the geometry
refiner.
Also lifts five SetParameterBlockConstant calls out of a per-observation loop in the detector solve,
where they were executing once per observation to say the same thing.
The rotation hoist was checked against the function it replaces on 200000 random dual numbers,
including the small-angle branch, comparing the value and all seventeen derivative lanes: no
difference in any component. Merged output is byte-identical on a 16 Mpx set and an ordinary one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011n8riB6X59oRjkrSHzNPAU