Transcendental production contract¶
This page is the static inventory and release contract for special-function calls in fused CUDA projections and the Helmert datum-shift kernel. It describes reachable projection math, not unused helpers that happen to be concatenated into an NVRTC source string.
Reading the inventory¶
For forward kernels, finite longitude offsets lambda are wrapped to
approximately [-pi, pi]. Latitude phi is not guarded inside each kernel, so
its bound is unknown at the kernel boundary. For inverse kernels, normalized
projected coordinates are likewise unknown/unbounded unless the row states an
explicit clamp. “Clamped” inverse-trigonometric arguments are provably in
[-1, 1]. All other derived bounds are marked unknown rather than inferred
from typical CRS usage.
The risk tier applies to changing the current implementation:
T0: no transcendental operation.
T1: retain native math; use the implemented same-argument native
sincospairing where both results are needed.T2: a bounded, guarded replacement with operation and coordinate error contracts exists.
T3: unknown/unbounded, singular, or iterative domain. Keep native until a separately guarded domain and error proof are added.
native.libdevice includes separate native calls and paired native sincos.
Pairing is an exact-library baseline optimization, not approximate accelerated
coverage. “Pair” below means both outputs for the same argument are reachable
in the same kernel section, and every pair listed is implemented through the
shared native pairing helper (or the equivalent double-single helper).
Complete fused-kernel inventory¶
Family |
Direction |
Reachable operations |
Argument/domain bound |
Native same-argument pairs |
Current implementation |
Allowed action |
Risk |
|---|---|---|---|---|---|---|---|
|
forward |
none |
n/a |
none |
arithmetic only |
none |
T0 |
|
inverse |
none |
n/a |
none |
arithmetic only |
none |
T0 |
|
forward |
|
kernel-boundary |
phi |
<= pi/2 |
lambda |
<= pi |
|
inverse |
|
qualified ellipsoidal setup requires eight finite coefficients with |
cy |
<=M(89.9°) |
phi |
<=89.9° |
|
forward |
|
spherical automatic path requires |
phi |
<=89.9 degrees |
none |
|
|
inverse |
|
accelerated setup requires finite nonzero units, |
none |
|
shared sixth-order conformal-to-geodetic series; complete-warp exact native fallback |
T2 |
|
forward |
|
|
none |
|
native only |
T3 |
|
inverse |
|
normalized northing and exponent: unbounded |
none |
|
native only |
T3 |
|
forward |
three |
general TM derived arguments: unknown; qualified UTM guard: ` |
lambda |
<= 0.06 |
asinh_arg |
<= 0.06 |
|
inverse |
|
inverse complex coordinates: unknown/unbounded |
pair |
|
paired native only |
T3 |
|
forward |
|
spherical/ellipsoidal 1SP/2SP regular cones require finite setup, signed nonzero units, exact |
pair |
|
spherical log/exp power; ellipsoidal native outer power with exp/atanh inner correction; complete-warp native fallback |
T2 |
|
inverse |
|
same setup except no |
none |
|
spherical logarithmic reconstruction; ellipsoidal native outer power plus bounded six-step exp/atanh recovery and a sixth-step contraction correction when |
T2 |
|
forward |
|
adjusted |
pair |
|
paired native only |
T3 |
|
inverse |
|
public ellipsoidal A/B north/south and C south domains; accelerated uniform guard requires |
none |
|
qualified Q1.62 iterative sine in five exact domains; native otherwise |
T2 |
|
forward |
|
|
pair |
|
paired native only |
T3 |
|
inverse |
|
projected radius unknown; exact authalic poles accepted within the shared |
q |
>qp` is atomically invalid |
none |
|
|
forward |
|
finite latitude restricted to |
lambda |
<= pi |
pair authalic latitude; pair |
|
|
inverse |
|
exact normalized disk enforced for oblique/equatorial and polar modes; center and poles explicit |
pair central angle |
|
paired native only |
T3 |
|
forward |
|
kernel-boundary |
none |
|
native only |
T3 |
|
inverse |
iterative polynomial, |
authalic inverse input clamped; spherical and ellipsoidal q inversion share the same helper; component-wise non-finite behavior matches fused execution |
pair |
|
paired native only |
T3 |
|
forward |
|
|
none |
|
native only |
T3 |
|
inverse |
iterative |
exact authalic poles accepted within the shared |
q |
>qp` is atomically invalid |
none |
|
|
forward |
|
kernel-boundary |
phi |
<= pi/2 |
lambda |
<= pi |
|
inverse |
|
exact spherical-equatorial domain after CRS setup canonicalization; accelerated reframe requires finite non-axis |
phi_argument |
<= 0.95 |
algebraic |
|
|
forward |
|
exact spherical equatorial/north-pole/south-pole/oblique origin domains; visible only when |
pair |
|
paired native only; horizon and hidden hemisphere return non-finite coordinates |
T3 |
|
inverse |
|
exact spherical origin domains; explicit bounded path requires equatorial or ` |
cos(phi0) |
>= 0.5 |
reciprocal-square-root normalization removes both |
|
|
forward |
|
|
pair |
|
paired native only |
T3 |
|
inverse |
two clamped |
both |
none |
|
native only |
T3 |
|
forward |
|
|
1 |
`; remaining derived arguments depend on CRS/domain |
pair |
|
|
inverse |
|
|
1 |
`; exponential and projected inputs unbounded |
pair |
|
|
forward |
|
inverse-trig inputs not explicitly clamped; |
pair |
|
paired native only |
T3 |
|
inverse |
|
exact standard-Bessel regular/north-oriented setup; accelerated coordinates require positive finite radius and finite intermediates with recovered ` |
phi |
<= 80 degrees` |
pair |
|
|
forward |
|
|
pair iterative/output |
|
paired native only |
T3 |
|
inverse |
clamped |
both inverse-trig arguments clamped |
pair |
|
paired native only |
T1 |
|
forward |
|
|
pair |
|
paired native only |
T3 |
|
inverse |
|
|
pair |
|
paired native only |
T3 |
|
forward |
|
conformal |
pair conformal latitude; pair scaled longitude |
|
paired native only |
T3 |
|
inverse |
|
one |
pair central angle; iterative pair |
|
paired native only |
T3 |
|
forward |
|
Sweep X/Y explicit; finite latitude bounded; Q1.62 guards require valid satellite geometry and |
pair geocentric latitude; pair |
|
qualified guarded pairs; exact native fallback for uncertain visibility, invalid parameters, or scale |
T2 |
|
inverse |
paired |
principal scan angles enforced; CPU uses a strict zero discriminant tolerance, while CUDA admits only the measured dtype-specific tangent bin ( |
pair x scan angle; pair y scan angle |
|
paired native only |
T3 |
|
forward |
none (table polynomial) |
n/a |
none |
arithmetic/table only |
none |
T0 |
|
inverse |
none (table polynomial/Newton) |
n/a |
none |
arithmetic/table only |
none |
T0 |
|
forward |
|
|
pair |
|
paired native only |
T3 |
|
inverse |
iterative |
projected initial values and iteration domain unknown; |
pair |
|
paired native only |
T3 |
|
forward |
none (polynomial) |
n/a |
none |
arithmetic only |
none |
T0 |
|
inverse |
none (polynomial/Newton) |
n/a |
none |
arithmetic only |
none |
T0 |
|
forward |
paired |
explicit spherical CRS only; antipode is singular; ellipsoidal, Modified, and Guam methods are rejected before dispatch |
pair |
|
paired native only |
T3 |
|
inverse |
|
explicit spherical CRS only; projected radius unknown; ellipsoidal, Modified, and Guam methods are rejected before dispatch |
pair central distance |
|
paired native only |
T3 |
|
datum shift (forward or inverse pipeline) |
paired |
Q1.62 guard ` |
angle |
<= pi |
pair source latitude; pair source longitude; pair final latitude with height |
native paired |
AEA, LAEA, Equal Earth, and CEA use one neutral CPU/xp authalic helper for
q, pole snapping, and q inversion. Its spherical branch is exact, its
ellipsoidal branch uses the stable atanh(e sin(phi))/e form, and only NumPy
may terminate Newton iteration early. Other array namespaces execute a fixed
iteration count without reading a device scalar or synchronizing to the host.
Coverage matrix¶
The user-facing coverage matrix is intentionally narrower than the inventory:
ID |
Family |
Direction |
Precision |
Device qualification |
Auto min elements |
Guarded operations |
|---|---|---|---|---|---|---|
|
|
forward/inverse/Helmert |
all supported |
universal fallback |
0 |
all special math |
|
|
datum shift |
all public modes (Helmert kernel stays fp64) |
Ada |
131,072 |
|
|
|
forward UTM |
fp64 |
Ada |
n/a |
paired |
|
|
spherical forward |
fp64 |
Ada |
524,288 |
Q1.62 |
|
|
ellipsoidal inverse |
fp64 |
Ada |
1 |
native meridional/derivative expressions and ten-step cap with |
|
|
ellipsoidal inverse hot domain |
fp64 |
Ada |
n/a |
two |
|
|
forward |
fp64 |
Ada |
262,144 |
Q1.62 paired |
|
|
inverse, spherical equatorial only |
fp64 |
Ada |
524,288 |
guarded algebraic reframe for normalized |
|
|
inverse, spherical equatorial/bounded-oblique only |
fp64 |
Ada |
n/a |
guarded reciprocal-square-root reframe for |
|
|
inverse, ellipsoidal A/B north/south and C south |
fp64 |
Ada |
1,000,000 |
Q1.62 sine inside |
|
|
forward, sphere/ellipsoid, sweep x/y |
fp64 |
Ada |
2,097,152 |
Q1.62 pairs for geocentric latitude and longitude; complete-native visibility-uncertainty fallback plus launch-uniform finite geometry/ |
|
|
forward, spherical north/south polar only |
fp64 |
Ada |
1,048,576 |
Q1.62 paired longitude trig; exact pole/antipode/non-finite handling and |
|
|
spherical forward A/B |
fp64 |
Ada |
262,144 |
removes the zero-exponent |
|
|
ellipsoidal forward A/B |
fp64 |
Ada |
n/a |
product reframe and degree-eight exponential polynomial; |
|
|
inverse, spherical/ellipsoidal A/B |
fp64 |
Ada |
65,536 |
native |
|
|
spherical/ellipsoidal 1SP/2SP forward regular cones |
fp64 |
Ada |
65,536 |
log/exp or native-outer-power conformal reframe; exact finite setup, |
|
|
spherical/ellipsoidal 1SP/2SP inverse |
fp64 |
Ada |
128 |
logarithmic or native-outer-power conformal reconstruction; six-step |
|
|
standard-Bessel inverse, regular and north oriented |
fp64 |
Ada |
n/a |
setup-derived exact Bessel domain, guarded log-ratio and sixth-order conformal recovery; positive finite radius, finite intermediates, ` |
tests/test_transcendental_coverage.py binds these IDs and capabilities to
the public registry and resolver. Adding a documented accelerated row without
registry support, or registry support without updating the contract, fails the
test. Native-only inventory rows do not imply an accelerated registry entry.
For a domain with multiple future hardware variants, the resolver filters
policy, backend, compute capability, fp32:fp64 ratio, and precision first, then
chooses the highest explicit registry priority. An equal-priority eligible tie
is rejected as ambiguous; registration order is never a tie-breaker.
Qualification and benchmark protocol¶
Run the end-to-end policy benchmark, not only an isolated operation benchmark:
uv run python benchmarks/bench_transcendental_policy.py \
--case all --n 5000000 --warmup 10 --iterations 30 --repeats 3 \
--json benchmark-results.json --enforce-gates
Each result records the GPU and compute capability, requested policy and
resolved implementation IDs, workload size, family/direction, compute
precision, point count, warmup and iteration counts, interleaved CUDA-event
samples and distribution, synchronized public-dispatch wall samples and
distribution, throughput, speedup against native, coordinate errors against
native and pyproj, and normal plus guard-edge domains. CUDA-event intervals
measure device execution only. Synchronized wall intervals use a host monotonic
clock around the warmed public transform_buffers() call and completion, so
they include normalization, device detection, cached strategy resolution,
argument preparation, submission, and synchronization. Pre-allocate and reuse
all device buffers. Separate untimed steady-state calls wrap CuPy’s allocator directly,
so even an allocation satisfied from the memory pool is counted. A CUDA stream
capture reports every kernel, memcpy, and memset graph node and the returned
objects are checked against the caller’s output buffers. CUDA graph labels are
reported verbatim; the benchmark does not infer a host/device transfer
direction from a memory-pool delta or a hard-coded constant. --enforce-gates
exits nonzero if any required gate fails.
For every registry entry with a physical-scale ceiling, untimed public probes
at nextafter(max_scale, +inf) and 1e12 m mechanically require the fixed
StrategyDecision to remain selected while both output arrays match native
bit-for-bit. This distinguishes host strategy fallback from the kernel’s
uniform scale guard; normal per-coordinate argument guards follow the same
principle without changing the selected ID.
GEOS forward additionally proves its satellite geometry independently of
coordinate lanes. Its uniform guard accepts only positive finite h and H,
requires H != h and the exact setup relation H == h + a, then passes a
through the shared 0 < scale <= 6,400,000 m gate. The setup contract bounds
h / a <= 1e10; tests span valid h from 1 m through that ceiling. Because
the perturbed line-of-sight denominator is at least h, the final h output
scale cancels rather than magnifying the Q1.62 angular error. Tests at the
scale limit and nextafter(6,400,000, +inf) require accelerated and bit-exact
native behavior respectively.
The default workload grid covers 1 through 5,000,000 elements on logarithmic
steps for every accelerated qualification case. Each case also injects its
exact min_elements - 1 and
min_elements boundary sizes. auto must resolve native below the registry’s
threshold and the qualified implementation at or above it; native must
remain native, and explicit accelerated must resolve the exact qualified ID.
The small-size gate permits at most 2% aggregate and 5% per-repeat
wall variation between identical native implementations; this is measurement
noise tolerance, not a performance claim. At and above min_elements, every
tested grid size must show at least 5% wall-clock improvement in all three
repeats. Explicit accelerated ignores min_elements and is measured at every
size, but no small-array speed claim is made for that override.
Expected kernel counts follow pipeline topology, not a universal one-launch claim:
Topology |
Expected fused kernel nodes |
|---|---|
one projection, no datum work |
1 |
geographic-only Helmert or SVD correction |
1 |
Helmert or SVD plus one projection |
2 |
projected-to-projected with one datum stage |
3 |
Helmert plus SVD plus one projection |
3 |
projected-to-projected with Helmert plus SVD |
4 |
Preallocated final outputs belong only to the final stage. Multi-stage paths
use four-array scratch slots per Transformer, keyed by input CUDA device and
normalized stream pointer. Slots are locked while host work is enqueued and
grow by doubling. The cache is LRU-bounded to eight leased slots per device.
Growth or eviction retains in-flight arrays behind recorded completion events
and prunes them only after an event query reports completion; it never
synchronizes. If all eight entries are leased, overflow scratch is transient
and event-retired instead of entering the cache. A warmed call at or below a
slot’s capacity must not allocate again. Every supplied final out_x, out_y,
and (when z is supplied) out_z is written and returned as the identical
object. No topology may add copy or memset nodes merely to route intermediate
x/y coordinates.
stream=None resolves the current stream inside the input array’s CUDA device.
The legacy null stream (device_id == -1) binds through that enclosing device
context; an explicit stream with a nonnegative, mismatched device ID is
rejected. This applies before scratch selection, so cache keys cannot silently
mix devices.
Each Transformer owns one persistent chunk workspace per CUDA device. Its lock
serializes a complete transform_chunked() call on that Transformer/device;
separate devices or Transformer instances remain independent. Within the call,
two persistent non-blocking streams and their pinned-host/device slots preserve
double-buffer overlap. Streams and slots are reused across calls and grow only
when capacity or z support increases. This makes repeated calls allocation-free
for internal workspace while preventing concurrent callers from racing over
the same staging buffers.
Qualification record¶
Dated benchmark results, accepted and rejected experiments, and wave-by-wave decision history live in qualification record. Potential future work is tracked separately in the experimental roadmap.
Those experimental documents explain why the registry has its current shape.
They do not define production behavior; this inventory, the central immutable
registry, and tests/test_transcendental_coverage.py do.
Go/no-go gates¶
A new implementation is no-go unless all of the following pass:
No correctness regression against native and the existing pyproj oracle thresholds, including normal, boundary-adjacent, non-finite, and out-of-domain inputs.
Every replaced operation has an explicit numeric bound over its guarded domain, plus an end-to-end coordinate-error bound. Unknown/unbounded inputs take native behavior.
Median device-execution and synchronized public-dispatch wall speedups are each at least 5% (
speedup >= 1.05) in three independent repeats at every size enabled forauto. Report all samples and p05/p50/p95; one favorable run is insufficient. Below that size,autoremains native and must pass the no-wall-regression noise bound.Native and accelerated policies match the expected stage topology. Direct allocator instrumentation reports zero steady-state allocation calls, CUDA graph capture reports no unplanned copy/memset/kernel nodes, and returned objects are the caller’s preallocated final buffers.
Native behavior is available on every device and for every unqualified family, direction, precision, domain, and non-finite input.
Hardware qualification is literal. H100 acceleration requires three stable H100 repeats and H100 accuracy results; RTX 4090/Ada evidence cannot qualify Hopper or a generic “datacenter” class.
Adding a reusable implementation¶
Give the implementation a stable, descriptive ID. Do not encode transient benchmark numbers or a private kernel symbol in it.
Describe family, direction, operation set, precision, device predicate, guarded domain, error contract, and fallback in the central immutable registry.
Keep resolution pure and inspectable through
explain_strategy(). Bothautoand explicitacceleratedmust explain native fallback.Reuse the implementation only where the argument proof is valid. Similar syntax (
sin(x)) is not evidence that two projection domains are the same.Extend the coverage-contract test and this inventory, then run the three-repeat end-to-end benchmark on every architecture being enabled.
Preserve one fused launch per mathematical stage and device residency, reuse intermediate scratch, and complete the GPU and pre-land review checklists before landing.