Skip to content

Expose IsDense, HasAnyDenseDimensions, and ToDenseTensor #115435

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 9 commits into from
May 12, 2025
26 changes: 17 additions & 9 deletions src/libraries/System.Numerics.Tensors/System.Numerics.Tensors.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36105.17 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{9F20CEA1-2216-4432-BBBD-F01E05D17F23}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bcl.Numerics", "..\Microsoft.Bcl.Numerics\src\Microsoft.Bcl.Numerics.csproj", "{1578185F-C4FA-4866-936B-E62AAEDD03B7}"
Expand Down Expand Up @@ -33,11 +37,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{7AC4B2C7-A55
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{841A2FA4-A95F-4612-A8B9-AD2EF769BC71}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "tools\gen", "{A21C99E7-E22B-470E-BF48-56B00AFE3D34}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{A21C99E7-E22B-470E-BF48-56B00AFE3D34}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "tools\src", "{25B37C75-C737-4AE8-9260-74A79870C8B8}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{25B37C75-C737-4AE8-9260-74A79870C8B8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "tools\ref", "{9482D7C5-F37C-40FC-B057-A16C1ED1C121}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{9482D7C5-F37C-40FC-B057-A16C1ED1C121}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}"
EndProject
Expand Down Expand Up @@ -105,23 +109,27 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9F20CEA1-2216-4432-BBBD-F01E05D17F23} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
{46AD9423-D8C3-44BB-A201-1CCCAB4C6DAF} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
{4AF6A02D-82C8-4898-9EDF-01F107C25061} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
{1578185F-C4FA-4866-936B-E62AAEDD03B7} = {DF0561A1-3AB8-4B51-AFB4-392EE1DD6247}
{848DD000-3D22-4A25-A9D9-05AFF857A116} = {DF0561A1-3AB8-4B51-AFB4-392EE1DD6247}
{21CB448A-3882-4337-B416-D1A3E0BCFFC5} = {7AC4B2C7-A55C-4C4F-9B02-77F5CBFFF4AB}
{848DD000-3D22-4A25-A9D9-05AFF857A116} = {DF0561A1-3AB8-4B51-AFB4-392EE1DD6247}
{46AD9423-D8C3-44BB-A201-1CCCAB4C6DAF} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
{4AF6A02D-82C8-4898-9EDF-01F107C25061} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
{D9283CC0-07E1-417A-B73C-223F3EB7A277} = {841A2FA4-A95F-4612-A8B9-AD2EF769BC71}
{DB954E01-898A-4FE2-A3AA-180D041AB08F} = {841A2FA4-A95F-4612-A8B9-AD2EF769BC71}
{04FC0651-B9D0-448A-A28B-11B1D4A897F4} = {A21C99E7-E22B-470E-BF48-56B00AFE3D34}
{683A7D28-CC55-4375-848D-E659075ECEE4} = {A21C99E7-E22B-470E-BF48-56B00AFE3D34}
{A21C99E7-E22B-470E-BF48-56B00AFE3D34} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
{1CBEAEA8-2CA1-4B07-9930-35A785205852} = {25B37C75-C737-4AE8-9260-74A79870C8B8}
{BA7828B1-7953-47A0-AE5A-E22B501C4BD0} = {25B37C75-C737-4AE8-9260-74A79870C8B8}
{25B37C75-C737-4AE8-9260-74A79870C8B8} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
{57E57290-3A6A-43F8-8764-D4DC8151F89C} = {9482D7C5-F37C-40FC-B057-A16C1ED1C121}
{A21C99E7-E22B-470E-BF48-56B00AFE3D34} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
{25B37C75-C737-4AE8-9260-74A79870C8B8} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
{9482D7C5-F37C-40FC-B057-A16C1ED1C121} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {10A5F2C3-5230-4916-9D4D-BBDB94851037}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{683a7d28-cc55-4375-848d-e659075ecee4}*SharedItemsImports = 5
..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{ba7828b1-7953-47a0-ae5a-e22b501c4bd0}*SharedItemsImports = 5
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ namespace System.Numerics.Tensors
public partial interface IReadOnlyTensor
{
nint FlattenedLength { get; }
bool HasAnyDenseDimensions { get; }
bool IsDense { get; }
bool IsEmpty { get; }
bool IsPinned { get; }
object this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get; }
Expand Down Expand Up @@ -87,6 +89,7 @@ public partial interface IReadOnlyTensor<TSelf, T> : System.Collections.Generic.
TSelf Slice(params scoped System.ReadOnlySpan<System.Buffers.NIndex> startIndexes);
TSelf Slice(params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges);
TSelf Slice(params scoped System.ReadOnlySpan<nint> startIndexes);
TSelf ToDenseTensor();
bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan<T> destination);
bool TryFlattenTo(scoped System.Span<T> destination);
}
Expand Down Expand Up @@ -138,6 +141,8 @@ public readonly ref partial struct ReadOnlyTensorSpan<T>
public ReadOnlyTensorSpan(T[]? array, int start, scoped System.ReadOnlySpan<nint> lengths, scoped System.ReadOnlySpan<nint> strides) { throw null; }
public static System.Numerics.Tensors.ReadOnlyTensorSpan<T> Empty { get { throw null; } }
public nint FlattenedLength { get { throw null; } }
public bool HasAnyDenseDimensions { get { throw null; } }
public bool IsDense { get { throw null; } }
public bool IsEmpty { get { throw null; } }
public ref readonly T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
public System.Numerics.Tensors.ReadOnlyTensorSpan<T> this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get { throw null; } }
Expand Down Expand Up @@ -805,6 +810,8 @@ public readonly ref partial struct TensorSpan<T>
public TensorSpan(T[]? array, int start, scoped System.ReadOnlySpan<nint> lengths, scoped System.ReadOnlySpan<nint> strides) { throw null; }
public static System.Numerics.Tensors.TensorSpan<T> Empty { get { throw null; } }
public nint FlattenedLength { get { throw null; } }
public bool HasAnyDenseDimensions { get { throw null; } }
public bool IsDense { get { throw null; } }
public bool IsEmpty { get { throw null; } }
public ref T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
public System.Numerics.Tensors.TensorSpan<T> this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get { throw null; } set { } }
Expand Down Expand Up @@ -863,6 +870,8 @@ public sealed partial class Tensor<T> : System.Collections.Generic.IEnumerable<T
internal Tensor() { }
public static System.Numerics.Tensors.Tensor<T> Empty { get { throw null; } }
public nint FlattenedLength { get { throw null; } }
public bool HasAnyDenseDimensions { get { throw null; } }
public bool IsDense { get { throw null; } }
public bool IsEmpty { get { throw null; } }
public bool IsPinned { get { throw null; } }
public ref T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
Expand Down Expand Up @@ -915,6 +924,7 @@ void System.Numerics.Tensors.ITensor.Fill(object value) { }
static System.Numerics.Tensors.Tensor<T> System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>.Create(scoped System.ReadOnlySpan<nint> lengths, scoped System.ReadOnlySpan<nint> strides, bool pinned) { throw null; }
static System.Numerics.Tensors.Tensor<T> System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>.CreateUninitialized(scoped System.ReadOnlySpan<nint> lengths, bool pinned) { throw null; }
static System.Numerics.Tensors.Tensor<T> System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>.CreateUninitialized(scoped System.ReadOnlySpan<nint> lengths, scoped System.ReadOnlySpan<nint> strides, bool pinned) { throw null; }
public Tensor<T> ToDenseTensor() { throw null; }
public string ToString(scoped System.ReadOnlySpan<nint> maximumLengths) { throw null; }
public bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan<T> destination) { throw null; }
public bool TryFlattenTo(scoped System.Span<T> destination) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,20 @@
<Right>lib/net9.0/System.Numerics.Tensors.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:System.Numerics.Tensors.IReadOnlyTensor`2.ToDenseTensor</Target>
<Left>lib/net8.0/System.Numerics.Tensors.dll</Left>
<Right>lib/net8.0/System.Numerics.Tensors.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:System.Numerics.Tensors.IReadOnlyTensor`2.ToDenseTensor</Target>
<Left>lib/net9.0/System.Numerics.Tensors.dll</Left>
<Right>lib/net9.0/System.Numerics.Tensors.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0017</DiagnosticId>
<Target>M:System.Numerics.Tensors.IReadOnlyTensor`2.AsReadOnlyTensorSpan(System.ReadOnlySpan{System.Buffers.NIndex})$0</Target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ public interface IReadOnlyTensor
/// <summary>Gets the total number of items in the tensor.</summary>
nint FlattenedLength { get; }

/// <summary>Determines if the current tensor has any dimension where <c>GetDimensionSpan(int)</c> will iterate through tensors that would have <see cref="IsDense" /> be <c>true</c>.</summary>
/// <remarks>
/// <para>This does not include the last dimension, <c>GetDimensionSpan(Rank - 1)</c>, as it always iterates 1 element at a time and would mean this property always returns true.</para>
/// <para>An example of a tensor which is not dense but which would have a dense dimension is a 2x2 Tensor where <c>FlattenedLength: 4; Lengths: [2, 2]; Strides: [4, 1]</c>. In such a scenario, the overall tensor is not dense because the backing storage has a length of at least 6 and so has 2 used elements, 2 unused elements, followed by the last 2 used elements. However, the two slices representing <c>[0..1, ..]</c> and <c>[1..2, ..]</c> would themselves be dense; thus <c>GetDimension(0).GetSlice(n)</c> will iterate dense tensors: <c>FlattenedLength: 2, Length: [2], Strides: [1]</c>.</para>
/// </remarks>
bool HasAnyDenseDimensions { get; }

/// <summary>Determines if the current tensor is dense.</summary>
/// <remarks>
/// <para>A dense tensor is one where the elements are ordered sequentially in memory and where no gaps exist between the elements.</para>
/// <para>For a 2x2 Tensor, this would mean it has <c>FlattenedLength: 4; Lengths: [2, 2]; Strides: [2, 1]</c>. The elements would be sequentially accessed via indexes: <c>[0, 0]; [0, 1]; [1, 0]; [1, 1]</c></para>
/// </remarks>
bool IsDense { 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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ public interface IReadOnlyTensor<TSelf, T> : IReadOnlyTensor, IEnumerable<T>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="ranges" /> is larger than the tensor.</exception>
TSelf Slice(params scoped ReadOnlySpan<NRange> ranges);

/// <summary>Creates a dense tensor from the elements of the current tensor.</summary>
/// <returns>The current tensor if it is already dense; otherwise, a new tensor that contains the elements of this tensor.</returns>
/// <remarks>
/// <para>A dense tensor is one where the elements are ordered sequentially in memory and where no gaps exist between the elements.</para>
/// <para>For a 2x2 Tensor, this would mean it has <c>FlattendLength: 4; Lengths: [2, 2]; Strides: [4, 1]</c>. The elements would be sequentially accessed via indexes: <c>[0, 0]; [0, 1]; [1, 0]; [1, 1]</c></para>
/// </remarks>
TSelf ToDenseTensor();

/// <summary>Attempts to copy the contents of this tensor into a destination tensor span and returns a value to indicate whether or not the operation succeeded.</summary>
/// <param name="destination">The target of the copy operation.</param>
/// <returns><see langword="true"/> if the copy operation succeeded; otherwise, <c>false</c>.</returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,11 @@ public ReadOnlyTensorSpan<T> this[params scoped ReadOnlySpan<NRange> ranges]
/// <inheritdoc cref="IReadOnlyTensor.FlattenedLength" />
public nint FlattenedLength => _shape.FlattenedLength;

internal bool IsContiguousAndDense => _shape.IsContiguousAndDense;
/// <inheritdoc cref="IReadOnlyTensor.HasAnyDenseDimensions" />
public bool HasAnyDenseDimensions => _shape.HasAnyDenseDimensions;

/// <inheritdoc cref="IReadOnlyTensor.IsDense" />
public bool IsDense => _shape.IsDense;

/// <inheritdoc cref="IReadOnlyTensor.IsEmpty" />
public bool IsEmpty => _shape.IsEmpty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,7 @@ public static Tensor<T> Reshape<T>(this Tensor<T> tensor, ReadOnlySpan<nint> len
if (tensor.Lengths.SequenceEqual(lengths))
return tensor;

if (!tensor.IsContiguousAndDense && !tensor.Strides.Contains(0))
if (!tensor.IsDense && !tensor.Strides.Contains(0))
{
ThrowHelper.ThrowArgument_CannotReshapeNonContiguousOrDense();
}
Expand Down Expand Up @@ -1513,7 +1513,7 @@ public static TensorSpan<T> Reshape<T>(in this TensorSpan<T> tensor, scoped Read
if (tensor.Lengths.SequenceEqual(lengths))
return tensor;

if (!tensor.IsContiguousAndDense && !tensor.Strides.Contains(0))
if (!tensor.IsDense && !tensor.Strides.Contains(0))
{
ThrowHelper.ThrowArgument_CannotReshapeNonContiguousOrDense();
}
Expand Down Expand Up @@ -1589,7 +1589,7 @@ public static ReadOnlyTensorSpan<T> Reshape<T>(in this ReadOnlyTensorSpan<T> ten
if (tensor.Lengths.SequenceEqual(lengths))
return tensor;

if (!tensor.IsContiguousAndDense && !tensor.Strides.Contains(0))
if (!tensor.IsDense && !tensor.Strides.Contains(0))
{
ThrowHelper.ThrowArgument_CannotReshapeNonContiguousOrDense();
}
Expand Down
Loading
Loading