Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/core/compatibility/11.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ See [Breaking changes in ASP.NET Core 11](/aspnet/core/breaking-changes/11/overv
| [SafeFileHandle.IsAsync and FileStream.IsAsync accurately reflect non-blocking state on Unix](core-libraries/11/safefilehandle-isasync-unix.md) | Behavioral change |
| [TAR-reading APIs verify header checksums when reading](core-libraries/11/tar-checksum-validation.md) | Behavioral change |
| [TarWriter uses HardLink entries for hard-linked files](core-libraries/11/tarwriter-hardlink-entries.md) | Behavioral change |
| [Tensor operations align equivalent shapes and empty tensors](core-libraries/11/tensor-shape-alignment.md) | Behavioral change |
| [Tensor operations reject unsupported storage layouts](core-libraries/11/tensor-storage-layout-validation.md) | Behavioral change |
| [ZipArchive.CreateAsync eagerly loads ZIP archive entries](core-libraries/11/ziparchive-createasync-eager-load.md) | Behavioral change |

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: "Breaking change - Tensor operations align equivalent shapes and empty tensors"
description: "Learn about the breaking change in .NET 11 where tensor operations use consistent shape-alignment rules."
ms.date: 10/06/2026
ai-usage: ai-assisted
ms.custom: https://github.com/dotnet/docs/issues/56305
---

# Tensor operations align equivalent shapes and empty tensors

Starting in .NET 11, tensor operations use consistent shape-alignment rules. Default rank-zero empty tensors and spans have an effective shape of `[0]` during computations, and operations can ignore redundant leading singleton dimensions when they align shapes.

The change is delivered in the [System.Numerics.Tensors](https://www.nuget.org/packages/System.Numerics.Tensors) package, including its supported target frameworks. Updating the package can affect apps that target earlier .NET versions.

## Version introduced

.NET 11

## Previous behavior

Tensor operations handled shapes inconsistently. Some operations required exact shape matches, while others aligned dimensions differently. As a result, equivalent shapes with redundant leading singleton dimensions, such as `[1, 1, 3]` and `[3]`, could be rejected or interpreted differently across operations.

Default empty tensors and spans retained rank-zero metadata, but operations didn't consistently treat them as vectors with an effective shape of `[0]`. Stack and concatenate operations could also interpret an axis differently based on the input ranks.

Some operations also narrowed logical element counts or offsets to `int`, which prevented native-backed tensor spans with more than `int.MaxValue` elements from being traversed correctly. The `EqualsAny`, `GreaterThanAny`, `GreaterThanOrEqualAny`, `LessThanAny`, and `LessThanOrEqualAny` operations didn't consistently inspect the full logical input length, including for empty inputs.

## New behavior

Tensor operations now use shared shape-alignment rules:

- Default rank-zero empty tensors and spans have an effective shape of `[0]` for computations. Their stored `Rank`, `Lengths`, and `Strides` don't change, and explicitly ranked empty shapes retain their dimensions.
- Operations can add or remove redundant leading singleton dimensions when they align shapes. For example, `[1, 1, 3]` aligns with `[3]`, but `[2, 1]` and `[1, 2]` remain distinct. Zero-length dimensions and non-leading singleton dimensions remain significant.
- Shape equality ignores only redundant leading singleton dimensions. It doesn't broadcast other dimensions.
- Stack and concatenate operations interpret the axis by using the first input's effective shape. Other inputs and destinations align to that shape.
- Default empty values can broadcast to `[2, 0]`. A binary operation between effective shapes `[0]` and `[0, 2]` rejects the incompatible trailing dimensions.
- Sources and destinations retain their requested shape metadata when operations align them.

Native-backed tensor spans can now be traversed with native-sized lengths and offsets, including spans with more than `int.MaxValue` logical elements. Empty views also retain a storage origin within their source. The `EqualsAny`, `GreaterThanAny`, `GreaterThanOrEqualAny`, `LessThanAny`, and `LessThanOrEqualAny` operations now inspect the full logical input range and handle empty inputs correctly.

## Type of breaking change

This is a [behavioral change](../../categories.md#behavioral-change).

## Reason for change

Consistent shape rules make tensor operations more predictable and preserve explicitly requested dimensions while allowing equivalent shapes to work together. Native-sized traversal also lets operations cover the full logical range of spans backed by larger storage.

For more information, see [dotnet/runtime#135060](https://github.com/dotnet/runtime/pull/135060).

## Recommended action

Review code that depends on a tensor operation accepting or rejecting a particular shape combination. Account for default rank-zero empty values as having an effective shape of `[0]`, and for redundant leading singleton dimensions to be ignored during alignment and shape comparison. Explicit zero-length dimensions and non-leading singleton dimensions remain significant.

For stack and concatenate operations, interpret the axis relative to the first input's effective shape. If your code requires exact stored ranks or lengths, validate that metadata before calling the operation. The stored metadata of default empty values doesn't change.

## Affected APIs

- <xref:System.Numerics.Tensors.Tensor.Broadcast*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.BroadcastTo*?displayProperty=nameWithType>, and <xref:System.Numerics.Tensors.Tensor.TryBroadcastTo*?displayProperty=nameWithType>
- Elementwise and copy operations on <xref:System.Numerics.Tensors.Tensor> that align tensor shapes or write to a caller-provided destination
- <xref:System.Numerics.Tensors.Tensor.Concatenate*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.ConcatenateOnDimension*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.Stack*?displayProperty=nameWithType>, and <xref:System.Numerics.Tensors.Tensor.StackAlongDimension*?displayProperty=nameWithType>
- <xref:System.Numerics.Tensors.Tensor.Reshape*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.Split*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.SqueezeDimension*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.Unsqueeze*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.PermuteDimensions*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.SetSlice*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.SequenceEqual*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.ResizeTo*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.Reverse*?displayProperty=nameWithType>, and <xref:System.Numerics.Tensors.Tensor.ReverseDimension*?displayProperty=nameWithType>
- <xref:System.Numerics.Tensors.Tensor.EqualsAny*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.GreaterThanAny*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.GreaterThanOrEqualAny*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.LessThanAny*?displayProperty=nameWithType>, and <xref:System.Numerics.Tensors.Tensor.LessThanOrEqualAny*?displayProperty=nameWithType>
- <xref:System.Numerics.Tensors.Tensor.IndexOfMax*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.IndexOfMaxMagnitude*?displayProperty=nameWithType>, <xref:System.Numerics.Tensors.Tensor.IndexOfMin*?displayProperty=nameWithType>, and <xref:System.Numerics.Tensors.Tensor.IndexOfMinMagnitude*?displayProperty=nameWithType>
2 changes: 2 additions & 0 deletions docs/core/compatibility/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ items:
href: core-libraries/11/tar-checksum-validation.md
- name: TarWriter uses HardLink entries for hard-linked files
href: core-libraries/11/tarwriter-hardlink-entries.md
- name: Tensor operations align equivalent shapes and empty tensors
href: core-libraries/11/tensor-shape-alignment.md
- name: Tensor operations reject unsupported storage layouts
href: core-libraries/11/tensor-storage-layout-validation.md
- name: ZipArchive.CreateAsync eagerly loads ZIP archive entries
Expand Down
2 changes: 2 additions & 0 deletions docs/standard/tensor-shapes-and-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ ai-usage: ai-generated

The [System.Numerics.Tensors](https://www.nuget.org/packages/System.Numerics.Tensors) package provides <xref:System.Numerics.Tensors.Tensor`1>, <xref:System.Numerics.Tensors.TensorSpan`1>, and <xref:System.Numerics.Tensors.ReadOnlyTensorSpan`1> for multidimensional data. Tensor shapes describe the logical dimensions; strides describe the distance, in elements, between successive positions along each dimension.

The behavior described here ships in the package across its supported target frameworks. Updating the package can affect apps that target earlier .NET versions.

These types share many conventions with NumPy, but they aren't interchangeable. Account for the following differences when you port an algorithm.

## Empty shapes and scalar-like results
Expand Down
Loading