|
Uni20
Asynchronous tensor and runtime library.
|
Status: general one-or-more-axis CPU sum reduction is implemented; synthetic diagonal views and trace front ends remain design work.
For a generic dense tensor, trace should be implemented as:
It should not be treated as a special high-level tensor operation in the dense backend.
This note is about dense tensor data. Symmetric tensors may expose a trace-like operation, but that operation should first lower through sector/block logic and then call dense primitives on the relevant blocks.
Full-reduction result residency is a separate front-end decision. See Scalar Tensors, Host Scalars, and Storage Transfer for the distinction between a rank-zero Tensor result and an ordinary host scalar.
Given an input tensor with shape and element strides, tracing axes a and b requires:
The diagonal of those two axes is represented as a synthetic axis t with extent:
and stride:
The surviving axes retain their input strides. The trace is then:
where:
So trace is a partial reduction over a strided view.
This motivates two important dense tensor primitives:
With those primitives, matrix diagonal, vector sum, tensor trace, partial trace, and many related operations are all special cases of the same mechanism.
The implemented sum_reduction_op<R, N> and CPU reference executor provide the second primitive for ordinary tensor axes. The executor preserves logical surviving-axis order, traverses canonical input and output layouts in their natural physical order, and respects non-default accessors. Trace still needs the first primitive: a synthetic diagonal view whose accessor/mapping combines the traced strides before invoking the same reduction machinery.
For example:
The public output axis order should normally be the input axis order with the traced axes removed. That logical order does not have to be the same as the physical traversal order used by the backend.
A dense trace implementation should build survivor records:
Then, for backend execution:
input_stride.Coalesce adjacent physical axes when:
For non-coalescable survivor axes, increasing input stride is the natural default physical order. It gives the smallest-stride input dimension the fastest-varying output coordinate, improving locality without changing logical semantics.
A custom kernel can implement this directly, but the primitive is also a natural match for backend libraries that support strided reductions.
For example, cuTENSOR has tensor descriptors with explicit strides and a generic partial reduction operation. A dense GPU trace can be expressed as a reduction over the synthetic diagonal axis whose stride is stride[a] + stride[b]. This is a better primitive than materializing an identity tensor or routing trace through a general contraction.
Backend selection can still choose a custom kernel for unsupported dtypes, small fixed cases, or builds without the relevant backend library. The design point is that the operation being selected is a strided reduction, not a special trace kernel.
Trace at the level of a block-sparse quantum-number-aware tensor is a different operation. It may involve sector constraints, dual leg conventions, block matching, and representation data.
The symmetric trace should therefore lower into a set of dense trace/reduction operations over blocks after the relevant sector logic has been resolved. The dense primitive layer should not be burdened with quantum-number semantics.