SemanticCompute v1.12.0
SemanticCompute v1.12.0 — the fused labelwise scatter
A minor, by the rule: one additive family (catalogue 148 → 149) plus new public API, and one correctness
fix in a shipped family that the new family's own cross-validation exposed. This is the release for anyone
sweeping a segmentation labelmap once per statistic: the requesting audit measured the same 512³ label volume
traversed five to six times per refresh — ~8×10⁹ voxel reads for what a single pass yields.
Added
Fused labelwise scatter — per-label bounding box + centroid + voxel count + intensity min/max/mean/variance
from ONE traversal of a label volume. Wanted labels are explicit (background has no hidden special case; ask
for id 0 and it is counted), routed through a host-built dense id→slot table in O(1) per voxel.
Three properties are contract, not accident, each pinned by its own test:
- Absolute coordinates. Bbox and centroid are in the volume's own voxel index space — never
crop-relative, never offset. Pinned with a label placed entirely in the far octant of an asymmetric
volume, so a crop-relative implementation cannot pass. The consumer pattern is crop-to-bbox-then-compute:
positions computed on the crop are crop-relative and the bbox min IS the origin that restores them. A
consumer of this release fixed exactly the bug this line prevents — a discarded crop origin rendering
plausible imagery of the wrong anatomy at full confidence. - Absence is unmistakable. A wanted label with zero voxels reports count 0, nil bbox and nil
centroid — never (0, 0, 0), which is a plausible position at the volume origin that downstream code
will happily accept as a real anchor (one consumer feeds centroids into a 12-DOF affine fit, where a
silent origin would drag the whole transform). - Exact and inexact are stated per field. Count and bbox are integer work: exact, blocking-invariant,
and verified BIT-EQUAL on GPU. Centroid and intensity sums are float folds in a fixed order —
deterministic per blocking, the same summation-order story every reduction family here tells. Variance is
clamped at zero.
The GPU form is two stages with no atomics: per-block private partials, then a fixed ascending-block fold
per label. Float atomics would make the result depend on thread completion order — the classic
irreproducible-metric bug; this is reproducible by construction, and the CPU reference computes the blocked
form identically so parity is not an accident of ordering.
Fixed
LabelwiseReduction could emit negative variance on near-constant input — latent since the family
shipped, found by the fused scatter's cross-validation against it. E[x²] − mean² cancels below zero in
float32; a negative variance is impossible as a statistic and becomes NaN at the consumer's first sqrt.
Clamped at zero in both the CPU reference and the GPU lowering, with a regression test. (The same
cross-validation first caught the new family's author misreading the old family's output layout. Both catches
are what cross-validating against existing families is for.)
Also in this release
The consumer-feedback inbox gains the mesh-scalar LUT interrogation filing (scattered trilinear probe +
transfer-function evaluation, both wanting CUDA lowerings) — recorded, accepted, queued for a future cycle.
Verification surface: 1,125 tests in 243 suites; the kernel-compile sweep covers 346 programs across 205
lowerings, 0 failed. Four lowering targets, three executed in-core (Metal, portable C, WGSL) plus the
externally verified CUDA runner.