Semantics helpers¶
anytensor.semantics
¶
Portable semantics for segment reductions and other cross-backend contracts.
This module is the source of truth for behaviors AnyTensor standardizes so
NumPy / JAX / Torch / TF agree. The user-facing write-up lives in
docs/semantics.md (MkDocs “Surprising differences”).
Empty-segment identities¶
============= ============== =========================
reduction floating integral
============= ============== =========================
sum 0 0
min +inf iinfo(dtype).max
max -inf iinfo(dtype).min
============= ============== =========================
Occupied slots always reflect the true reduction (including when the only
values are ±inf / NaN). Use segment_min_or_constant /
segment_max_or_constant when empty slots should be a finite fill instead
of the identity sentinel.
Surprises we paper over (standardized)¶
- TF
unsorted_segment_{min,max}— empty slots and ±inf-only segments become finfo limits. AnyTensor uses scatter from a ±inf / iinfo identity so empties and occupied ±inf match NumPy/JAX/Torch. - TF
tensor_scatter_nd_{min,max}— NaN updates are ignored (segment stays at the identity). After scatter we OR in per-segment NaN viaunsorted_segment_max(is_nan(x))so NaN-containing segments become NaN. num_segments— required shape-size (Python int / symbolic / 0-d integral tensor); never inferred fromsegment_ids(JAX convention).- TF graph
repeat/arange/*_like— Python scalar repeats stay Python; shim usestf.repeat/tf.range;*_likebuilds from symbolicshape(x)so polymorphictf.functiondoes not seeTensorShape(None,).
Surprises we document only (backend-local)¶
- Index width — Torch scatter casts to int64; JAX/TF often keep int32 (especially without JAX x64).
sorted=— honored on JAX/TF; no-op on NumPy/Torch (unsorted-safe).- Default float width — JAX may truncate float64→float32 without x64.
inf *subnormal / float32-min may beinf(NumPy, eager TF) vsnan(JAX, TF XLA) when the tiny flushes to 0. jax.jit+repeat— needs static repeats ortotal_repeat_length. Partition helpers requiretotal_length;num_segmentsisshape(partitions)[0].- TF XLA vs eager with NaN — eager → NaN;
jit_compile=Truemay → ±inf for min/max/maximum/minimum and similar. - Empty axis
min/max— length-0 is framework-defined (often error).
GPU notes (no GPU CI)¶
- Torch CUDA scatter still wants int64 ids (cast on Torch path).
- Outputs should stay on the input device (fills / arange / empty identities).
- Prefer float32 compares; GPU TF32 and float64 support vary.
- Equal-value tie order for min/max is not portable under atomics.
- Empty CUDA buffers and GPU XLA /
torch.compileare stricter than CPU; MPS ≠ CUDA.
empty_segment_identity
¶
Return the AnyTensor empty-segment identity for reduction on dtype.
This is the portable fill used for empty slots in segment_sum /
segment_min / segment_max (and backends that implement them).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dtype
|
Any
|
Target dtype (NumPy / Array API / TF dtype with
|
required |
reduction
|
str
|
One of |
required |
xp
|
Any
|
Array API-ish namespace with |
required |
Returns:
| Type | Description |
|---|---|
Any
|
|
Any
|
|
Notes
Differs from TF unsorted_segment_{min,max}, which fill empties
(and ±inf-only segments) with finfo limits. AnyTensor uses these
identities so empties and occupied ±inf match NumPy/JAX/Torch.