Skip to content

Rewrite of System.Numerics.Tensors to allow for more code sharing, various correctness fixes, and stability improvements #114927

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b4b1b2a
Refactor Tensor to be more reusable and validate appropriate state
tannergooding Mar 7, 2025
fa7461f
Handle Equals, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrE…
tannergooding Apr 11, 2025
60bdf20
Many implementations correctly swapped to new form. (#25)
michaelgsharp Apr 16, 2025
f84b134
more tensors updates (#26)
michaelgsharp Apr 17, 2025
077c181
Resolve a few build failures
tannergooding Apr 17, 2025
96e2ad4
Ensure SetSlice and ToString are working as expected
tannergooding Apr 17, 2025
f1b9583
Tensors lastfew (#27)
michaelgsharp Apr 21, 2025
c85f7ac
Merge remote-tracking branch 'dotnet/main' into tensors
tannergooding Apr 21, 2025
70b6a86
Minor cleanup of the Tensor files
tannergooding Apr 21, 2025
d5b0e8e
Ensure that tensor tests are building
tannergooding Apr 21, 2025
a32450f
Resolving various build failures due to API compatibility
tannergooding Apr 21, 2025
130b159
Ensure flattendLength is adjusted after the stride is set for that di…
tannergooding Apr 21, 2025
ccce86c
Ensure that we set linearLength if -1 is passed in when strides is empty
tannergooding Apr 21, 2025
3c40b5c
Ensure that the first index is correct
tannergooding Apr 21, 2025
e182c94
Cleanup to ensure iteration and construction initializes correctly
tannergooding Apr 21, 2025
95d74b6
Ensure that broadcasting is allowed to be in any stride position
tannergooding Apr 21, 2025
ec980e2
Have AreCompatible handle empty shapes
tannergooding Apr 21, 2025
06fa711
Ensure IndexOutOfRangeException is thrown for invalid indexes
tannergooding Apr 21, 2025
c39fd85
Ensure that the stride is set to 0 when the length of a dimension is …
tannergooding Apr 21, 2025
fa0be0e
Fixing Broadcasting Loop (#29)
michaelgsharp Apr 22, 2025
3f2032b
Merge remote-tracking branch 'dotnet/main' into tensors
tannergooding Apr 22, 2025
fd15e01
Ensure that minimumLinearLength is actually the minimum
tannergooding Apr 22, 2025
aaf9aae
Ensure the rented buffer is cleared
tannergooding Apr 22, 2025
9a60357
Fix the AreCompatible checks
tannergooding Apr 22, 2025
053a494
Tensor finishing (#30)
michaelgsharp Apr 22, 2025
eea881d
Merge remote-tracking branch 'dotnet/main' into tensors
tannergooding Apr 22, 2025
c6800b8
only2 tests left
michaelgsharp Apr 22, 2025
2f2788a
Update src/libraries/System.Numerics.Tensors/src/System/Numerics/Tens…
tannergooding Apr 23, 2025
aa0e7c0
Update compatibility suppressions
tannergooding Apr 23, 2025
1ecf899
transpose working
michaelgsharp Apr 23, 2025
9608f5a
reverse working
michaelgsharp Apr 23, 2025
798ea06
Merge branch 'main' into tensors
tannergooding Apr 23, 2025
ac449a0
Revert the unnecessary sln changes
tannergooding Apr 23, 2025
eb42165
Remove an unnecessary using
tannergooding Apr 23, 2025
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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@
<data name="ThrowArgument_SetSliceNoRange" xml:space="preserve">
<value>When no ranges are specified the values tensor must be equal in size as the input tensor.</value>
</data>
<data name="ThrowArgument_LengthsNotBroadcastCompatible" xml:space="preserve">
<value>Lengths are not broadcast compatible.</value>
<data name="ThrowArgument_LengthsNotCompatible" xml:space="preserve">
<value>Lengths are not compatible with each other.</value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lengths are not compatible with each other.

nit: Is this clear enough message to explain the failure?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exceptions need some cleanup to improve the messages in general. I don't think we should block the PR on this though.

</data>
<data name="ThrowArgument_SplitNotSplitEvenly" xml:space="preserve">
<value>The number of splits must perfectly divide the dimension.</value>
Expand Down Expand Up @@ -240,4 +240,7 @@
<data name="Arithmetic_NaN" xml:space="preserve">
<value>Function does not accept floating point Not-a-Number values.</value>
</data>
</root>
<data name="ThrowArgument_LengthIsNonZeroForNullReference" xml:space="preserve">
<value>The provided length is non zero while the data reference is null.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,8 @@
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<Compile Include="System\Numerics\Tensors\netcore\TensorShape.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorHelpers.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorExtensions.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Tensor.Factory.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Tensor.cs" />
<Compile Include="System\Numerics\Tensors\netcore\ITensor.cs" />
<Compile Include="System\Numerics\Tensors\netcore\IReadOnlyTensor.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorSpanDebugView.cs" />
<Compile Include="System\Numerics\Tensors\netcore\ReadOnlyTensorSpan.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorSpanHelpers.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorSpanHelpers.T.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorSpan.cs" />
<Compile Include="System\NIndex.cs" />
<Compile Include="System\NRange.cs" />
<Compile Include="System\Buffers\NIndex.cs" />
<Compile Include="System\Buffers\NRange.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Common\TensorPrimitives.IAggregationOperator.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Common\TensorPrimitives.IBinaryOperator.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Common\TensorPrimitives.IBooleanUnaryOperator.cs" />
Expand All @@ -44,6 +32,14 @@
<Compile Include="System\Numerics\Tensors\netcore\Common\TensorPrimitives.IUnaryOneToFourOperator.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Common\TensorPrimitives.IUnaryOperator.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Common\TensorPrimitives.IUnaryTwoToOneOperator.cs" />
<Compile Include="System\Numerics\Tensors\netcore\IReadOnlyTensor.cs" />
<Compile Include="System\Numerics\Tensors\netcore\IReadOnlyTensor_1.cs" />
<Compile Include="System\Numerics\Tensors\netcore\ITensor.cs" />
<Compile Include="System\Numerics\Tensors\netcore\ITensor_1.cs" />
<Compile Include="System\Numerics\Tensors\netcore\ReadOnlyTensorSpan_1.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Tensor.cs" />
<Compile Include="System\Numerics\Tensors\netcore\Tensor_1.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorOperation.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Abs.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Acos.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Acosh.cs" />
Expand Down Expand Up @@ -170,6 +166,9 @@
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.TrailingZeroCount.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Truncate.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorPrimitives.Xor.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorShape.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorSpan.cs" />
<Compile Include="System\Numerics\Tensors\netcore\TensorSpanDebugView.cs" />
</ItemGroup>

<ItemGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net9.0'))">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,181 +2,50 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace System.Numerics.Tensors
{

/// <summary>
/// Represents a read-only tensor.
/// </summary>
/// <summary>Represents a read-only tensor.</summary>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public interface IReadOnlyTensor
{
/// <summary>
/// Gets a value that indicates whether the collection is currently empty.
/// </summary>
/// <summary>Gets the specified element of the tensor.</summary>
/// <param name="indexes">The index of the element for which to get.</param>
/// <returns>The element that exists at <paramref name="indexes" />.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the following conditions is met:
/// * <paramref name="indexes" /> does not contain <see cref="Rank" /> elements
/// * <paramref name="indexes" /> contains an element that is negative or greater than or equal to the corresponding dimension length
/// </exception>
object? this[params scoped ReadOnlySpan<nint> indexes] { get; }

/// <inheritdoc cref="this[ReadOnlySpan{nint}]" />
object? this[params scoped ReadOnlySpan<NIndex> indexes] { get; }

/// <summary>Gets the total number of items in the tensor.</summary>
nint FlattenedLength { get; }

/// <summary>Gets a value indicating whether this tensor is empty.</summary>
/// <value><see langword="true"/> if this tensor is empty; otherwise, <see langword="false"/>.</value>
bool IsEmpty { get; }

/// <summary>
/// Gets a value that indicates whether the underlying buffer is pinned.
/// </summary>
/// <summary>Gets a value that indicates whether the underlying buffer is pinned.</summary>
bool IsPinned { get; }

/// <summary>
/// Gets the number of elements in the tensor.
/// </summary>
nint FlattenedLength { get; }

/// <summary>
/// Gets the number of dimensions in the tensor.
/// </summary>
int Rank { get; }

/// <summary>
/// Gets the length of each dimension in the tensor.
/// </summary>
/// <summary>Gets the length of each dimension in the tensor.</summary>
[UnscopedRef]
ReadOnlySpan<nint> Lengths { get; }

/// <summary>
/// Gets the stride of each dimension in the tensor.
/// </summary>
/// <summary>Gets the rank, or number of dimensions, in the tensor.</summary>
int Rank { get; }

/// <summary>Gets the stride of each dimension in the tensor.</summary>
[UnscopedRef]
ReadOnlySpan<nint> Strides { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to be used.</param>
object this[params scoped ReadOnlySpan<nint> indexes] { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to be used.</param>
object this[params scoped ReadOnlySpan<NIndex> indexes] { get; }

/// <summary>
/// Pins and gets a <see cref="MemoryHandle"/> to the backing memory.
/// </summary>
/// <summary>Pins and gets a <see cref="MemoryHandle"/> to the backing memory.</summary>
/// <returns><see cref="MemoryHandle"/></returns>
MemoryHandle GetPinnedHandle();
}

/// <summary>
/// Represents a read-only tensor.
/// </summary>
/// <typeparam name="TSelf">The type that implements this interface.</typeparam>
/// <typeparam name="T">The element type.</typeparam>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public interface IReadOnlyTensor<TSelf, T> : IReadOnlyTensor, IEnumerable<T>
where TSelf : IReadOnlyTensor<TSelf, T>
{
/// <summary>
/// Gets an empty tensor.
/// </summary>
static abstract TSelf? Empty { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to be used.</param>
new T this[params scoped ReadOnlySpan<nint> indexes] { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to be used.</param>
new T this[params scoped ReadOnlySpan<NIndex> indexes] { get; }

/// <summary>
/// Gets the values at the specified ranges.
/// </summary>
/// <param name="ranges">The ranges to be used.</param>
TSelf this[params scoped ReadOnlySpan<NRange> ranges] { get; }

/// <summary>
/// Creates a read-only tensor span for the entire underlying buffer.
/// </summary>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan();

/// <summary>
/// Creates a read-only tensor span for the specified start indexes.
/// </summary>
/// <param name="start">The start locations to be used.</param>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<nint> start);

/// <summary>
/// Creates a read-only tensor span for the specified start indexes.
/// </summary>
/// <param name="startIndex">The started indexes to be used.</param>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<NIndex> startIndex);

/// <summary>
/// Creates a read-only tensor span for the specified ranges.
/// </summary>
/// <param name="range">The ranges to be used.</param>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<NRange> range);

/// <summary>
/// Copies the tensor to the specified destination. The destination tensor must be equal to or larger than the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be copied to.</param>
void CopyTo(scoped TensorSpan<T> destination);

/// <summary>
/// Flattens the tensor to the specified destination. The destination span must be equal to or larger than the number of elements in the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be flattened to.</param>
void FlattenTo(scoped Span<T> destination);

/// <summary>
/// Returns a reference to the 0th element of the tensor. If the tensor is empty, returns <see langword="null"/>.
/// </summary>
/// <remarks>
/// This method can be used for pinning and is required to support the use of the tensor within a fixed statement.
/// </remarks>
ref readonly T GetPinnableReference();

/// <summary>
/// Slices the tensor using the specified start indexes.
/// </summary>
/// <param name="start">The start locations to be used.</param>
/// <returns>The sliced tensor.</returns>
TSelf Slice(params scoped ReadOnlySpan<nint> start);

/// <summary>
/// Slices the tensor using the specified start indexes.
/// </summary>
/// <param name="startIndex">The start indexes to be used.</param>
/// <returns>The sliced tensor.</returns>
TSelf Slice(params scoped ReadOnlySpan<NIndex> startIndex);

/// <summary>
/// Slices the tensor using the specified ranges.
/// </summary>
/// <param name="range">The ranges to be used.</param>
/// <returns>The sliced tensor.</returns>
TSelf Slice(params scoped ReadOnlySpan<NRange> range);

/// <summary>
/// Tries to copy the tensor to the specified destination. The destination tensor must be equal to or larger than the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be copied to.</param>
/// <returns><see langword="true" /> if the copy succeeded, <see langword="false" /> otherwise.</returns>
bool TryCopyTo(scoped TensorSpan<T> destination);

/// <summary>
/// Tries to flatten the tensor to the specified destination. The destination span must be equal to or larger than the number of elements in the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be flattened to.</param>
/// <returns><see langword="true" /> if the flatten succeeded, <see langword="false" /> otherwise.</returns>
bool TryFlattenTo(scoped Span<T> destination);
}
}
Loading
Loading