Skip to content

Commit fdbe38c

Browse files
Expose IsDense, HasAnyDenseDimensions, and ToDenseTensor (#115435)
* Expose IsDense, HasAnyDenseDimensions, and ToDenseTensor * Ensure HasAnyDenseDimensions is exposed by Tensor<T> * Fix spelling * Update CompatibilitySuppressions for S.N.Tensors as its experimental * Ensure minimumNonZeroStride is handled when 0 * Ensure the assert handles IsEmpty not being dense * Don't assert that dense spans aren't empty * Ensure slice sets HasAnyDenseDimensions * Don't assert that a non-dense array cannot have equal flattened and linear lengths
1 parent d2c5618 commit fdbe38c

File tree

11 files changed

+337
-32
lines changed

11 files changed

+337
-32
lines changed

src/libraries/System.Numerics.Tensors/System.Numerics.Tensors.sln

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
Microsoft Visual Studio Solution File, Format Version 12.00
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.14.36105.17 d17.14
5+
MinimumVisualStudioVersion = 10.0.40219.1
26
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{9F20CEA1-2216-4432-BBBD-F01E05D17F23}"
37
EndProject
48
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bcl.Numerics", "..\Microsoft.Bcl.Numerics\src\Microsoft.Bcl.Numerics.csproj", "{1578185F-C4FA-4866-936B-E62AAEDD03B7}"
@@ -33,11 +37,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{7AC4B2C7-A55
3337
EndProject
3438
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{841A2FA4-A95F-4612-A8B9-AD2EF769BC71}"
3539
EndProject
36-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "tools\gen", "{A21C99E7-E22B-470E-BF48-56B00AFE3D34}"
40+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{A21C99E7-E22B-470E-BF48-56B00AFE3D34}"
3741
EndProject
38-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "tools\src", "{25B37C75-C737-4AE8-9260-74A79870C8B8}"
42+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{25B37C75-C737-4AE8-9260-74A79870C8B8}"
3943
EndProject
40-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "tools\ref", "{9482D7C5-F37C-40FC-B057-A16C1ED1C121}"
44+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{9482D7C5-F37C-40FC-B057-A16C1ED1C121}"
4145
EndProject
4246
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}"
4347
EndProject
@@ -105,23 +109,27 @@ Global
105109
EndGlobalSection
106110
GlobalSection(NestedProjects) = preSolution
107111
{9F20CEA1-2216-4432-BBBD-F01E05D17F23} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
108-
{46AD9423-D8C3-44BB-A201-1CCCAB4C6DAF} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
109-
{4AF6A02D-82C8-4898-9EDF-01F107C25061} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
110112
{1578185F-C4FA-4866-936B-E62AAEDD03B7} = {DF0561A1-3AB8-4B51-AFB4-392EE1DD6247}
111-
{848DD000-3D22-4A25-A9D9-05AFF857A116} = {DF0561A1-3AB8-4B51-AFB4-392EE1DD6247}
112113
{21CB448A-3882-4337-B416-D1A3E0BCFFC5} = {7AC4B2C7-A55C-4C4F-9B02-77F5CBFFF4AB}
114+
{848DD000-3D22-4A25-A9D9-05AFF857A116} = {DF0561A1-3AB8-4B51-AFB4-392EE1DD6247}
115+
{46AD9423-D8C3-44BB-A201-1CCCAB4C6DAF} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
116+
{4AF6A02D-82C8-4898-9EDF-01F107C25061} = {DE94CA7D-BB10-4865-85A6-6B694631247F}
113117
{D9283CC0-07E1-417A-B73C-223F3EB7A277} = {841A2FA4-A95F-4612-A8B9-AD2EF769BC71}
114118
{DB954E01-898A-4FE2-A3AA-180D041AB08F} = {841A2FA4-A95F-4612-A8B9-AD2EF769BC71}
115119
{04FC0651-B9D0-448A-A28B-11B1D4A897F4} = {A21C99E7-E22B-470E-BF48-56B00AFE3D34}
116120
{683A7D28-CC55-4375-848D-E659075ECEE4} = {A21C99E7-E22B-470E-BF48-56B00AFE3D34}
117-
{A21C99E7-E22B-470E-BF48-56B00AFE3D34} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
118121
{1CBEAEA8-2CA1-4B07-9930-35A785205852} = {25B37C75-C737-4AE8-9260-74A79870C8B8}
119122
{BA7828B1-7953-47A0-AE5A-E22B501C4BD0} = {25B37C75-C737-4AE8-9260-74A79870C8B8}
120-
{25B37C75-C737-4AE8-9260-74A79870C8B8} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
121123
{57E57290-3A6A-43F8-8764-D4DC8151F89C} = {9482D7C5-F37C-40FC-B057-A16C1ED1C121}
124+
{A21C99E7-E22B-470E-BF48-56B00AFE3D34} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
125+
{25B37C75-C737-4AE8-9260-74A79870C8B8} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
122126
{9482D7C5-F37C-40FC-B057-A16C1ED1C121} = {F9C2AAB1-C7B0-4E43-BB18-4FB16F6E272B}
123127
EndGlobalSection
124128
GlobalSection(ExtensibilityGlobals) = postSolution
125129
SolutionGuid = {10A5F2C3-5230-4916-9D4D-BBDB94851037}
126130
EndGlobalSection
131+
GlobalSection(SharedMSBuildProjectFiles) = preSolution
132+
..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{683a7d28-cc55-4375-848d-e659075ecee4}*SharedItemsImports = 5
133+
..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{ba7828b1-7953-47a0-ae5a-e22b501c4bd0}*SharedItemsImports = 5
134+
EndGlobalSection
127135
EndGlobal

src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ namespace System.Numerics.Tensors
5959
public partial interface IReadOnlyTensor
6060
{
6161
nint FlattenedLength { get; }
62+
bool HasAnyDenseDimensions { get; }
63+
bool IsDense { get; }
6264
bool IsEmpty { get; }
6365
bool IsPinned { get; }
6466
object this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get; }
@@ -87,6 +89,7 @@ public partial interface IReadOnlyTensor<TSelf, T> : System.Collections.Generic.
8789
TSelf Slice(params scoped System.ReadOnlySpan<System.Buffers.NIndex> startIndexes);
8890
TSelf Slice(params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges);
8991
TSelf Slice(params scoped System.ReadOnlySpan<nint> startIndexes);
92+
TSelf ToDenseTensor();
9093
bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan<T> destination);
9194
bool TryFlattenTo(scoped System.Span<T> destination);
9295
}
@@ -138,6 +141,8 @@ public readonly ref partial struct ReadOnlyTensorSpan<T>
138141
public ReadOnlyTensorSpan(T[]? array, int start, scoped System.ReadOnlySpan<nint> lengths, scoped System.ReadOnlySpan<nint> strides) { throw null; }
139142
public static System.Numerics.Tensors.ReadOnlyTensorSpan<T> Empty { get { throw null; } }
140143
public nint FlattenedLength { get { throw null; } }
144+
public bool HasAnyDenseDimensions { get { throw null; } }
145+
public bool IsDense { get { throw null; } }
141146
public bool IsEmpty { get { throw null; } }
142147
public ref readonly T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
143148
public System.Numerics.Tensors.ReadOnlyTensorSpan<T> this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get { throw null; } }
@@ -805,6 +810,8 @@ public readonly ref partial struct TensorSpan<T>
805810
public TensorSpan(T[]? array, int start, scoped System.ReadOnlySpan<nint> lengths, scoped System.ReadOnlySpan<nint> strides) { throw null; }
806811
public static System.Numerics.Tensors.TensorSpan<T> Empty { get { throw null; } }
807812
public nint FlattenedLength { get { throw null; } }
813+
public bool HasAnyDenseDimensions { get { throw null; } }
814+
public bool IsDense { get { throw null; } }
808815
public bool IsEmpty { get { throw null; } }
809816
public ref T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
810817
public System.Numerics.Tensors.TensorSpan<T> this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get { throw null; } set { } }
@@ -863,6 +870,8 @@ public sealed partial class Tensor<T> : System.Collections.Generic.IEnumerable<T
863870
internal Tensor() { }
864871
public static System.Numerics.Tensors.Tensor<T> Empty { get { throw null; } }
865872
public nint FlattenedLength { get { throw null; } }
873+
public bool HasAnyDenseDimensions { get { throw null; } }
874+
public bool IsDense { get { throw null; } }
866875
public bool IsEmpty { get { throw null; } }
867876
public bool IsPinned { get { throw null; } }
868877
public ref T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
@@ -915,6 +924,7 @@ void System.Numerics.Tensors.ITensor.Fill(object value) { }
915924
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; }
916925
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; }
917926
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; }
927+
public Tensor<T> ToDenseTensor() { throw null; }
918928
public string ToString(scoped System.ReadOnlySpan<nint> maximumLengths) { throw null; }
919929
public bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan<T> destination) { throw null; }
920930
public bool TryFlattenTo(scoped System.Span<T> destination) { throw null; }

src/libraries/System.Numerics.Tensors/src/CompatibilitySuppressions.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,20 @@
337337
<Right>lib/net9.0/System.Numerics.Tensors.dll</Right>
338338
<IsBaselineSuppression>true</IsBaselineSuppression>
339339
</Suppression>
340+
<Suppression>
341+
<DiagnosticId>CP0006</DiagnosticId>
342+
<Target>M:System.Numerics.Tensors.IReadOnlyTensor`2.ToDenseTensor</Target>
343+
<Left>lib/net8.0/System.Numerics.Tensors.dll</Left>
344+
<Right>lib/net8.0/System.Numerics.Tensors.dll</Right>
345+
<IsBaselineSuppression>true</IsBaselineSuppression>
346+
</Suppression>
347+
<Suppression>
348+
<DiagnosticId>CP0006</DiagnosticId>
349+
<Target>M:System.Numerics.Tensors.IReadOnlyTensor`2.ToDenseTensor</Target>
350+
<Left>lib/net9.0/System.Numerics.Tensors.dll</Left>
351+
<Right>lib/net9.0/System.Numerics.Tensors.dll</Right>
352+
<IsBaselineSuppression>true</IsBaselineSuppression>
353+
</Suppression>
340354
<Suppression>
341355
<DiagnosticId>CP0017</DiagnosticId>
342356
<Target>M:System.Numerics.Tensors.IReadOnlyTensor`2.AsReadOnlyTensorSpan(System.ReadOnlySpan{System.Buffers.NIndex})$0</Target>

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/IReadOnlyTensor.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ public interface IReadOnlyTensor
2626
/// <summary>Gets the total number of items in the tensor.</summary>
2727
nint FlattenedLength { get; }
2828

29+
/// <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>
30+
/// <remarks>
31+
/// <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>
32+
/// <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>
33+
/// </remarks>
34+
bool HasAnyDenseDimensions { get; }
35+
36+
/// <summary>Determines if the current tensor is dense.</summary>
37+
/// <remarks>
38+
/// <para>A dense tensor is one where the elements are ordered sequentially in memory and where no gaps exist between the elements.</para>
39+
/// <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>
40+
/// </remarks>
41+
bool IsDense { get; }
42+
2943
/// <summary>Gets a value indicating whether this tensor is empty.</summary>
3044
/// <value><see langword="true"/> if this tensor is empty; otherwise, <see langword="false"/>.</value>
3145
bool IsEmpty { get; }

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/IReadOnlyTensor_1.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ public interface IReadOnlyTensor<TSelf, T> : IReadOnlyTensor, IEnumerable<T>
8282
/// <exception cref="ArgumentOutOfRangeException"><paramref name="ranges" /> is larger than the tensor.</exception>
8383
TSelf Slice(params scoped ReadOnlySpan<NRange> ranges);
8484

85+
/// <summary>Creates a dense tensor from the elements of the current tensor.</summary>
86+
/// <returns>The current tensor if it is already dense; otherwise, a new tensor that contains the elements of this tensor.</returns>
87+
/// <remarks>
88+
/// <para>A dense tensor is one where the elements are ordered sequentially in memory and where no gaps exist between the elements.</para>
89+
/// <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>
90+
/// </remarks>
91+
TSelf ToDenseTensor();
92+
8593
/// <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>
8694
/// <param name="destination">The target of the copy operation.</param>
8795
/// <returns><see langword="true"/> if the copy operation succeeded; otherwise, <c>false</c>.</returns>

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan_1.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,11 @@ public ReadOnlyTensorSpan<T> this[params scoped ReadOnlySpan<NRange> ranges]
299299
/// <inheritdoc cref="IReadOnlyTensor.FlattenedLength" />
300300
public nint FlattenedLength => _shape.FlattenedLength;
301301

302-
internal bool IsContiguousAndDense => _shape.IsContiguousAndDense;
302+
/// <inheritdoc cref="IReadOnlyTensor.HasAnyDenseDimensions" />
303+
public bool HasAnyDenseDimensions => _shape.HasAnyDenseDimensions;
304+
305+
/// <inheritdoc cref="IReadOnlyTensor.IsDense" />
306+
public bool IsDense => _shape.IsDense;
303307

304308
/// <inheritdoc cref="IReadOnlyTensor.IsEmpty" />
305309
public bool IsEmpty => _shape.IsEmpty;

src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,7 +1440,7 @@ public static Tensor<T> Reshape<T>(this Tensor<T> tensor, ReadOnlySpan<nint> len
14401440
if (tensor.Lengths.SequenceEqual(lengths))
14411441
return tensor;
14421442

1443-
if (!tensor.IsContiguousAndDense && !tensor.Strides.Contains(0))
1443+
if (!tensor.IsDense && !tensor.Strides.Contains(0))
14441444
{
14451445
ThrowHelper.ThrowArgument_CannotReshapeNonContiguousOrDense();
14461446
}
@@ -1513,7 +1513,7 @@ public static TensorSpan<T> Reshape<T>(in this TensorSpan<T> tensor, scoped Read
15131513
if (tensor.Lengths.SequenceEqual(lengths))
15141514
return tensor;
15151515

1516-
if (!tensor.IsContiguousAndDense && !tensor.Strides.Contains(0))
1516+
if (!tensor.IsDense && !tensor.Strides.Contains(0))
15171517
{
15181518
ThrowHelper.ThrowArgument_CannotReshapeNonContiguousOrDense();
15191519
}
@@ -1589,7 +1589,7 @@ public static ReadOnlyTensorSpan<T> Reshape<T>(in this ReadOnlyTensorSpan<T> ten
15891589
if (tensor.Lengths.SequenceEqual(lengths))
15901590
return tensor;
15911591

1592-
if (!tensor.IsContiguousAndDense && !tensor.Strides.Contains(0))
1592+
if (!tensor.IsDense && !tensor.Strides.Contains(0))
15931593
{
15941594
ThrowHelper.ThrowArgument_CannotReshapeNonContiguousOrDense();
15951595
}

0 commit comments

Comments
 (0)