Robotics operators & conventions ================================ GLASS carries a set of **robotics-specialized small operators** alongside the BLAS/LAPACK surface — the fixed-size device primitives that every GPU robotics stack otherwise hand-rolls, each with its own (frequently colliding) sign and storage conventions. They are organized by the workload they serve: * **Rigid-body dynamics** — the Featherstone spatial 6-D kit: the cross products (``motion_cross`` / ``force_cross`` / ``force_cross_dual`` and their fused ``*_mul`` applies), the coordinate transforms (``motion_transform`` / ``force_transform`` with fused/inverse applies — ``force_transform_mul`` is the RNEA back-pass ``Xᵀ·f``), and the 10-parameter spatial inertia (``spatial_inertia`` / ``spatial_inertia_mul``) that every RNEA/ABA/CRBA kernel and analytic dynamics gradient is built from. * **Manifold states (floating bases, orientations)** — the SO(3)/SE(3)/ quaternion family: ``skew``, ``so3_exp``/``so3_log``, the right/left Jacobians and inverses, the SE(3) retract with its 6x6 first derivatives and 6x6x6 second derivative, the quaternion primitive set (``quat_mul``/``quat_exp``/``quat_log``/``quat_rotate``/``quat_to_rot``/…), and the pose-error metrics (``quat_error``/``pose_error``/``quat_angle`` plus the ``log_cosh`` smoother — IK residuals and goal costs). * **Constrained trajectory optimization** — second-order-cone projection (``soc_project``), PHR augmented-Lagrangian scalars, the relaxed log-barrier, and the planar-angle utilities (``angle_wrap``/``angle_diff``/``angle_lerp``). * **Sampling-based control** — max-shifted ``softmax``/``logsumexp`` (the MPPI path-integral weight update) and the signed ``argmax``/``argmin`` index-payload reductions. * **Collision checking** — sphere-sphere/sphere-box signed distances with gradients, ``transform_sphere``, the branchless ``frame_from_vector`` tangent basis, and ``segment_segment_closest``. * **Estimation & registration** — the deterministic 3x3 spectral kit: ``eig3`` (fixed-sweep serial Jacobi), ``svd3``, and ``closest_rotation`` (the polar rotation factor with the det fix — also the Kabsch/Wahba/Umeyama best-fit rotation and the rotation-matrix re-orthonormalizer). Why these live in GLASS rather than in each consumer: the ops are small, recur across dynamics/planning/control/estimation, and are **error-prone to hand-roll** — sign conventions, storage order, and small-angle branches are exactly where independent implementations silently disagree. One tested, convention-pinned home removes that class of bug (the formulas here are promoted from Pinocchio-validated generated code and from numpy-oracle- validated solver kernels, then re-validated against scipy and finite-difference identities in ``test/test_robotics.py``). Conventions (read before calling anything) ------------------------------------------ The conventions below are **load-bearing**; a wrong guess at any of them produces plausible-looking wrong numbers, not crashes. Spatial (Featherstone) vectors — angular first A spatial motion vector is ``v = [ω(3); v_lin(3)]`` and a spatial force vector is ``f = [n(3); f_lin(3)]`` (moment first). This is the Featherstone/MuJoCo ordering used by the ``motion_cross``/``force_cross`` family. 6x6 matrices are column-major. Spatial transforms — the ``(E, r)`` pair, never a packed 6x6 A coordinate transform is carried as the rotation ``E`` (3x3, A→B) plus the origin offset ``r`` (B's origin in A). ``motion_transform_mul`` applies Featherstone's ``ᴮX_A = [[E, 0], [−E·[r]ₓ, E]]``; ``INVERSE = true`` applies the inverse map directly from the same pair. The force transform is ``X* = X⁻ᵀ``, and ``force_transform_mul`` is exactly the RNEA back-pass ``Xᵀ·f``. Spatial inertia — GRiD's 10-parameter regressor basis ``pi = [m, h(3) = m·c, I_O(6) = [Ixx, Ixy, Ixz, Iyy, Iyz, Izz]]`` with ``I_O`` about the body-frame ORIGIN (not the COM). Pinocchio's dynamic parameters pack the six inertia entries in a different order (``Ixx, Ixy, Iyy, Ixz, Iyz, Izz``) — permute when crossing. SE(3) tangents — separate ``(ρ, φ)`` arguments, linear-first blocks The Lie-family ops never take a packed 6-vector twist: the linear part ``ρ`` and angular part ``φ`` are separate 3-vector arguments, so there is no input-ordering trap. Output 6x6/6x6x6 blocks index the tangent as ``[ρ; φ]`` (linear first), matching Pinocchio's ``dIntegrate``. Note this is the OPPOSITE half of the field from the Featherstone family above — each family keeps its native literature convention; permute explicitly when crossing between them. Quaternions — Hamilton, compile-time storage layout All quaternions are Hamilton quaternions. The storage order is the compile-time ``QuatLayout`` tag: ``xyzw`` (default — Eigen/Warp/cuRobo storage) or ``wxyz`` (MuJoCo/Ceres/GTSAM/ROS). The math is written once against accessor indices; the two layouts are pure storage permutations of each other (a pytest gate). ``quat_exp`` takes the FULL rotation vector and halves internally. Matrices — column-major, GLASS-wide 3x3 and 6x6 outputs are column-major (``M[c*3 + r]`` / ``J[c*6 + r]``); the SE(3) Hessian is six stacked column-major 6x6 slices (``J2[k*36 + c*6 + r]``). Pose errors — compile-time ``ErrorFrame`` tag, shortest path Both frames express the tangent step FROM ``q_des`` TO ``q``; only the resolving frame differs (pinocchio ``ReferenceFrame`` precedent). ``ErrorFrame::LOCAL`` (default): ``log(q_des⁻¹ ⊗ q)`` — body frame, ``quat_retract(q_des, e) == q`` (GTSAM ``localCoordinates`` / manif ``rminus``); pair with BODY-frame Jacobians. ``ErrorFrame::WORLD``: ``log(q ⊗ q_des⁻¹) = R(q_des)·e_LOCAL`` — pair with WORLD-frame geometric Jacobians (IK, visual servoing, task-space control). Swapping the arguments negates the error in either frame (a residual written ``log(q_des ⊗ q⁻¹)`` is the WORLD form with swapped arguments). The double cover is always folded (``|e| ≤ π``); ``quat_angle`` is frame-invariant. ``pose_error`` is the DECOUPLED R³ × SO(3) error ``[p − p_des; quat_error]`` (what GPU goal costs minimize), not the coupled SE(3) log. Exact tangent Jacobian (LOCAL): identity on translation, ``Jr(e)⁻¹`` (``so3_right_jacobian_inv``) on rotation. Homogeneous 4x4 interop — the ``LDA`` tag ``quat_to_rot`` / ``rot_to_quat`` carry a leading-dimension template parameter (default 3). ``LDA = 4`` reads/writes the rotation block of a column-major 4x4 homogeneous transform IN PLACE (only the nine rotation entries are touched) — the ``gemv``/``gemm`` ``ROW_STRIDE`` pattern extended to the Lie corner, eliminating the 9-element repack at ``T[16*i]``-style call sites. Small-angle branches Every trigonometric map carries a Taylor head so it is smooth through θ = 0 (thresholds documented per function); ``so3_log`` routes through the Shepperd quaternion extraction so it is stable through θ = π; the inverse-Jacobian coefficient uses the half-angle form that is finite at θ = π. The SE(3) second-derivative chain computes in double regardless of the interface precision (validated against mpmath complex-step ground truth in its source project). 3x3 spectral conventions ``eig3`` returns the spectrum ASCENDING (``np.linalg.eigh`` parity, up to eigenvector signs); ``svd3`` returns singular values DESCENDING (``np.linalg.svd`` parity; U/V orthogonal, possibly det −1); ``closest_rotation`` always returns det +1. ``svd3`` routes through ``eig3(AᵀA)``, so small singular values are accurate to ~‖A‖·√ε (f32: ~3e-4·‖A‖) — use f64 where tight small-σ accuracy matters. Rank-deficient inputs are completed deterministically (a fixed representative of the standard SVD freedom). Tiers ----- Every **array-shaped** robotics op spans the three SIMT interfaces — block (``glass::block::``, re-exported as bare ``glass::``), warp (``glass::warp::``), thread (``glass::thread::``) — from one shared serial core: each active thread computes the small fixed-size result redundantly in registers and the tier strides the copy-out. That construction is thread-count **bit-invariant** at block scope (asserted at 1/32/64/256 threads) and keeps the three tiers within FMA-contraction jitter of each other (asserted at ≤4 ulp for arithmetic maps, tight relative tolerance for trig chains). Outputs must not alias inputs at block/warp scope. **Scalar-returning** ops (the angle utilities, the AL/barrier scalars, the geometry distances) are *tier-free*: they read no ``threadIdx`` and return by value, so the same bare-``glass::`` function is correct at any scope — there is nothing for a tier variant to change, and none exist by design. Fused vs composed ----------------- Each fused micro-kernel equals the composition of general kernels it replaces — ``motion_cross_mul(v, x)`` is exactly ``gemv(motion_cross(v), x)`` without the 36-element temporary, ``so3_exp`` is exactly ``quat_to_rot(quat_exp(φ))`` up to rounding — and the test suite asserts those equivalences. A hand-rolled copy of any of these formulas computes the same thing at the same speed; what it cannot give you is the pinned convention, the identity test suite, and the three tiers. Examples ``14``–``19`` under ``examples/`` walk one use case per family (spatial dynamics, SE(3) retract, MPPI weights, cone AL, sphere collision, best-fit rotation).