Segment ops¶
Required sizes, partition totals, and cache: Usage → Caller rules.
anytensor.segment
¶
Segment reductions and related helpers for ragged / GNN-style code.
Empty-segment identities are standardized in :mod:anytensor.semantics
(float ±inf, integer dtype min/max, sum 0).
num_segments is always required on segment ops (JAX convention).
Callers may pass a Python int, a jit/compile symbolic constant, or a 0-d
tensor scalar — never inferred from segment_ids (that would be
max(ids)+1, data-dependent). Partition helpers do not take
num_segments: it is shape(partitions)[0], a shape read. They do
require total_length (shape(logits)[0], not a data
sum(partitions)). Partition helpers call :func:partition_ids,
which uses :meth:cache.lookup / :meth:cache.store on "partition"
when a decorator (sticky across calls) / context / :meth:cache.enable
is active. If a cached expansion's
length does not match total_length (host Python ints), that entry
is purged, a warning is issued, and ids are recomputed; tracing skips
the check. :meth:cache.purge drops one tensor from one namespace.
partition_sum / min / max / softmax are that expansion
then the matching segment_* helper.
TorchScript: :func:enable_torchscript wraps segment_sum / min /
max with a torch.jit.is_scripting() divert. Import order does not
matter: a :func:module_if_loaded helper enables the divert as soon as
torch is imported. Eager calls still dispatch by tensor type
(NumPy / JAX / Torch / TF); only the scripted path uses
:mod:anytensor.torchscript. See docs/usage.md.
segment_sum
¶
Computes the sum within segments of an array.
Similar to :func:jax.ops.segment_sum and TF unsorted_segment_sum.
Reduces x along axis 0, summing rows that share the same
segment_ids entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values to sum. The leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer ids with |
required |
num_segments
|
ShapeSize
|
Required shape-size (unlike JAX, where omitting it
defaults to |
required |
sorted
|
bool
|
When True, JAX/TF may use a sorted-ids fast path. No-op on NumPy and Torch (unsorted-safe scatter). |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Array of shape |
SegmentOut
|
as |
Notes
Empty-segment identity is 0 for all dtypes
(:mod:anytensor.semantics).
Index width is backend-local: Torch casts ids to int64 at scatter;
JAX without jax_enable_x64 often keeps int32 and may warn on int64
ids.
Under torch.jit.script, import torch in either order relative to
AnyTensor — the divert auto-enables via :func:anytensor.module_if_loaded.
Eager calls still dispatch by tensor type; only the scripted path uses
:mod:anytensor.torchscript.
Examples:
>>> import numpy as np
>>> import anytensor as at
>>> x = np.arange(5.0)
>>> ids = np.array([0, 0, 1, 1, 2])
>>> at.segment_sum(x, ids, num_segments=3)
array([1., 5., 4.])
Source code in anytensor/segment.py
segment_max
¶
Computes the maximum within segments of an array.
Similar to :func:jax.ops.segment_max. Reduces x along axis 0 by
segment_ids.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values to reduce. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer ids with |
required |
num_segments
|
ShapeSize
|
Required shape-size (Python |
required |
sorted
|
bool
|
Honored on JAX/TF; no-op on NumPy/Torch. |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Array of shape |
Notes
Empty-slot identity is -inf / dtype min — not TF's native
unsorted_segment_max finfo fill. Occupied ±inf stays ±inf.
On TensorFlow, scatter ignores NaN updates; AnyTensor ORs NaN back in so a segment that saw any NaN is NaN (matches NumPy/JAX/Torch).
Prefer :func:segment_max_or_constant when empty slots should be a
finite fill instead of -inf.
Under TF XLA (tf.function(jit_compile=True)), NaN in min/max-like
ops may become ±inf instead of NaN — avoid relying on NaN under XLA.
TorchScript: :func:enable_torchscript (eager path stays multi-backend).
Source code in anytensor/segment.py
segment_min
¶
Computes the minimum within segments of an array.
Similar to :func:jax.ops.segment_min. Reduces x along axis 0 by
segment_ids.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values to reduce. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer ids with |
required |
num_segments
|
ShapeSize
|
Required shape-size (Python |
required |
sorted
|
bool
|
Honored on JAX/TF; no-op on NumPy/Torch. |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Array of shape |
Notes
Empty-slot identity is +inf / dtype max — not TF's native
unsorted_segment_min finfo fill. Occupied ±inf stays ±inf.
On TensorFlow, scatter ignores NaN updates; AnyTensor ORs NaN back in so a segment that saw any NaN is NaN (matches NumPy/JAX/Torch).
Prefer :func:segment_min_or_constant when empty slots should be a
finite fill instead of +inf.
Under TF XLA, NaN in min/max-like ops may become ±inf — avoid relying on NaN under XLA.
TorchScript: :func:enable_torchscript (eager path stays multi-backend).
Source code in anytensor/segment.py
enable_torchscript
¶
Enable torch.jit.script through public segment_sum / min / max.
Wraps those helpers with a torch.jit.is_scripting() divert to
:mod:anytensor.torchscript. Eager behavior is unchanged: NumPy, JAX,
Torch, and TF tensors still dispatch via backends. Only while scripting
(or inside an already-scripted graph) do we take the pure-Torch kernels.
That lets a third-party library call anytensor.segment_sum in ordinary
Python, while an end user of that library can torch.jit.script their
own code that reaches those calls.
Does not import torch and does not require a particular import order.
If Torch is not loaded yet, a helper is registered with
:func:anytensor.module_if_loaded and the divert enables on a later
import torch. Returns False until then; safe to call more than once.
Source code in anytensor/segment.py
segment_count
¶
Count how many elements fall in each segment.
Implemented as segment_sum of ones, so empty slots are 0.0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
segment_ids
|
SegmentIds
|
Integer ids (same conventions as :func: |
required |
num_segments
|
ShapeSize
|
Required shape-size (Python |
required |
sorted
|
bool
|
Forwarded to :func: |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Float vector of shape |
SegmentOut
|
|
SegmentOut
|
float32 on JAX without x64). |
Source code in anytensor/segment.py
segment_mean
¶
Mean of values of x within each segment along axis 0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values to average. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer segment ids (see :func: |
required |
num_segments
|
ShapeSize
|
Required shape-size. |
required |
sorted
|
bool
|
Forwarded to underlying segment ops (no-op on NumPy/Torch). |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Array of shape |
Notes
Empty segments yield 0 (sum is already 0; the denominator is clamped away from zero only so division stays defined). This differs from a NaN-on-empty mean.
Source code in anytensor/segment.py
segment_variance
¶
Population variance of x within each segment along axis 0.
Computed as the segment mean of squared deviations from the segment mean
(divide by n, not n-1).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer segment ids (see :func: |
required |
num_segments
|
ShapeSize
|
Required shape-size. |
required |
sorted
|
bool
|
Forwarded to underlying segment ops (no-op on NumPy/Torch). |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Array of shape |
SegmentOut
|
|
Source code in anytensor/segment.py
segment_normalize
¶
Divide each value by its segment sum (0/0 → 0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer segment ids (see :func: |
required |
num_segments
|
ShapeSize
|
Required shape-size. |
required |
sorted
|
bool
|
Forwarded to :func: |
False
|
Returns:
| Type | Description |
|---|---|
SegmentValues
|
Array with the same shape as |
SegmentValues
|
become |
Source code in anytensor/segment.py
segment_softmax
¶
Softmax within segments (numerically stable).
Subtracts the per-segment max before exp, then normalizes by the
per-segment sum of exps — same pattern as a stable full softmax.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logits
|
SegmentValues
|
Scores. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer segment ids (see :func: |
required |
num_segments
|
ShapeSize
|
Required shape-size (Python |
required |
sorted
|
bool
|
Forwarded to underlying segment ops (no-op on NumPy/Torch). |
False
|
Returns:
| Type | Description |
|---|---|
SegmentValues
|
Array with the same shape as |
SegmentValues
|
sum to |
SegmentValues
|
nothing useful if referenced via ids). |
Notes
Inherits empty-slot segment_max identity (-inf) and TF NaN
OR-in behavior from :func:segment_max / :func:segment_sum.
Not TorchScript-safe today (needs Python dispatch).
Source code in anytensor/segment.py
segment_min_or_constant
¶
Segment min with a finite fill for empty segments.
Like :func:segment_min, but empty slots become constant instead of
+inf / dtype max.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer segment ids (see :func: |
required |
num_segments
|
ShapeSize
|
Required shape-size. |
required |
constant
|
float
|
Fill for empty segments (default |
0.0
|
sorted
|
bool
|
Forwarded to :func: |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Array of shape |
Source code in anytensor/segment.py
segment_max_or_constant
¶
Segment max with a finite fill for empty segments.
Like :func:segment_max, but empty slots become constant instead of
-inf / dtype min.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
SegmentValues
|
Values. Leading axis is the segment axis. |
required |
segment_ids
|
SegmentIds
|
Integer segment ids (see :func: |
required |
num_segments
|
ShapeSize
|
Required shape-size. |
required |
constant
|
float
|
Fill for empty segments (default |
0.0
|
sorted
|
bool
|
Forwarded to :func: |
False
|
Returns:
| Type | Description |
|---|---|
SegmentOut
|
Array of shape |
Source code in anytensor/segment.py
partition_ids
¶
Expand partition lengths to segment ids ([0,0,…,1,1,…,n-1]).
This is the conversion other partition helpers call internally.
num_segments is shape(partitions)[0] (not an argument; not
data-dependent). total_length is the required flattened length
(shape(logits)[0], not a data sum(partitions)). Passed to
:func:repeat as total_repeat_length.
The only partition helper that talks to :data:cache. Uses
:meth:cache.lookup / :meth:cache.store on "partition". Outside
the cache, every call rebuilds ids. Inside, the same partitions
tensor returns the previous ids from cache["partition"] until
the tensor is collected or the block exits — one entry per
partition vector. The flattened total is shape(ids)[0] (not a
separate sum(partitions) cache); on ONNX export that length is a
dim_param. If a cached expansion's length does not match
total_length (in-place edit of a 0-d size, or a stale entry),
that entry is purged, a warning is issued, and ids are recomputed.
The length check uses host Python ints only; tracing skips it.
Passing None for total_length is a TypeError.
Source code in anytensor/segment.py
partition_sum
¶
Sum within contiguous partitions of lengths partitions.
Convenience: :func:partition_ids then :func:segment_sum.
num_segments is shape(partitions)[0] — not an argument.
total_length is required (shape(x)[0], not a data
sum(partitions)). Does not talk to :data:cache itself —
:func:partition_ids does, so a cache hit is shared with every
partition helper. If you already have ids, call :func:segment_sum.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ShapedArray
|
Values aligned with the flattened partitions (length
|
required |
partitions
|
IntArray
|
1-D integer vector of partition sizes. Length is the number of segments. |
required |
total_length
|
ShapeSize
|
Required shape-size for the flattened length
( |
required |
Returns:
| Type | Description |
|---|---|
ShapedArray
|
Array of shape |
ShapedArray
|
partitions are |
Source code in anytensor/segment.py
partition_min
¶
Minimum within contiguous partitions of lengths partitions.
Convenience: :func:partition_ids then :func:segment_min. Same
contracts as :func:partition_sum. Empty partitions keep the min
identity (+inf / dtype max). Prefer
:func:segment_min_or_constant after :func:partition_ids for a
finite empty fill.
Source code in anytensor/segment.py
partition_max
¶
Maximum within contiguous partitions of lengths partitions.
Convenience: :func:partition_ids then :func:segment_max. Same
contracts as :func:partition_sum. Empty partitions keep the max
identity (-inf / dtype min). Prefer
:func:segment_max_or_constant after :func:partition_ids for a
finite empty fill.
Source code in anytensor/segment.py
partition_softmax
¶
Softmax within contiguous partitions of lengths partitions.
Convenience: :func:partition_ids then :func:segment_softmax.
num_segments is shape(partitions)[0] — not an argument.
total_length is required (shape(logits)[0], not a data
sum(partitions)). Does not talk to :data:cache itself —
:func:partition_ids does, so a cache hit is shared with every
partition helper. Ids are rebuilt on every call unless that
cache is active. A compiler may CSE the rebuild; eager will not.
If you already have ids, call :func:segment_softmax.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logits
|
ShapedArray
|
Scores aligned with the flattened partitions (length
|
required |
partitions
|
IntArray
|
1-D integer vector of partition sizes. Length is the number of segments. |
required |
total_length
|
ShapeSize
|
Required shape-size for the flattened length
( |
required |
Returns:
| Type | Description |
|---|---|
ShapedArray
|
Softmax of |