Skip to content

Added in non-generic interfaces for Tensors #113401

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 4 commits into from
Mar 14, 2025
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,28 @@ namespace System.Buffers
}
namespace System.Numerics.Tensors
{
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public partial interface IReadOnlyTensor<TSelf, T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable where TSelf : System.Numerics.Tensors.IReadOnlyTensor<TSelf, T>
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5001", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public partial interface IReadOnlyTensor
{
static abstract TSelf? Empty { get; }
nint FlattenedLength { get; }
bool IsEmpty { get; }
bool IsPinned { get; }
T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get; }
TSelf this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get; }
T this[params scoped System.ReadOnlySpan<nint> indexes] { get; }
object this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get; }
object this[params scoped System.ReadOnlySpan<nint> indexes] { get; }
[System.Diagnostics.CodeAnalysis.UnscopedRefAttribute]
System.ReadOnlySpan<nint> Lengths { get; }
int Rank { get; }
[System.Diagnostics.CodeAnalysis.UnscopedRefAttribute]
System.ReadOnlySpan<nint> Strides { get; }
System.Buffers.MemoryHandle GetPinnedHandle();
}
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5001", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public partial interface IReadOnlyTensor<TSelf, T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor where TSelf : System.Numerics.Tensors.IReadOnlyTensor<TSelf, T>
{
static abstract TSelf? Empty { get; }
new T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get; }
TSelf this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get; }
new T this[params scoped System.ReadOnlySpan<nint> indexes] { get; }
System.Numerics.Tensors.ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan();
System.Numerics.Tensors.ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan<System.Buffers.NIndex> startIndex);
System.Numerics.Tensors.ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan<System.Buffers.NRange> range);
Expand All @@ -83,18 +90,25 @@ public partial interface IReadOnlyTensor<TSelf, T> : System.Collections.Generic.
bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan<T> destination);
bool TryFlattenTo(scoped System.Span<T> destination);
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public partial interface ITensor<TSelf, T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor<TSelf, T> where TSelf : System.Numerics.Tensors.ITensor<TSelf, T>
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5001", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public partial interface ITensor : System.Numerics.Tensors.IReadOnlyTensor
{
bool IsReadOnly { get; }
new object this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get; set; }
new object this[params scoped System.ReadOnlySpan<nint> indexes] { get; set; }
void Clear();
void Fill(object value);
}
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5001", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public partial interface ITensor<TSelf, T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor, System.Numerics.Tensors.IReadOnlyTensor<TSelf, T>, System.Numerics.Tensors.ITensor where TSelf : System.Numerics.Tensors.ITensor<TSelf, T>
{
new T this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get; set; }
new TSelf this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get; set; }
new T this[params scoped System.ReadOnlySpan<nint> indexes] { get; set; }
System.Numerics.Tensors.TensorSpan<T> AsTensorSpan();
System.Numerics.Tensors.TensorSpan<T> AsTensorSpan(params scoped System.ReadOnlySpan<System.Buffers.NIndex> startIndex);
System.Numerics.Tensors.TensorSpan<T> AsTensorSpan(params scoped System.ReadOnlySpan<System.Buffers.NRange> range);
System.Numerics.Tensors.TensorSpan<T> AsTensorSpan(params scoped System.ReadOnlySpan<nint> start);
void Clear();
static abstract TSelf Create(scoped System.ReadOnlySpan<nint> lengths, bool pinned = false);
static abstract TSelf Create(scoped System.ReadOnlySpan<nint> lengths, scoped System.ReadOnlySpan<nint> strides, bool pinned = false);
static abstract TSelf CreateUninitialized(scoped System.ReadOnlySpan<nint> lengths, bool pinned = false);
Expand Down Expand Up @@ -816,8 +830,8 @@ public ref partial struct Enumerator
public bool MoveNext() { throw null; }
}
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public sealed partial class Tensor<T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>, System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5001", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public sealed partial class Tensor<T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor, System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>, System.Numerics.Tensors.ITensor, System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>
{
internal Tensor() { }
public static System.Numerics.Tensors.Tensor<T> Empty { get { throw null; } }
Expand All @@ -831,12 +845,16 @@ internal Tensor() { }
public System.ReadOnlySpan<nint> Lengths { get { throw null; } }
public int Rank { get { throw null; } }
public System.ReadOnlySpan<nint> Strides { get { throw null; } }
object System.Numerics.Tensors.IReadOnlyTensor.this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
object System.Numerics.Tensors.IReadOnlyTensor.this[params scoped System.ReadOnlySpan<nint> indexes] { get { throw null; } }
System.ReadOnlySpan<nint> System.Numerics.Tensors.IReadOnlyTensor.Lengths { get { throw null; } }
System.ReadOnlySpan<nint> System.Numerics.Tensors.IReadOnlyTensor.Strides { get { throw null; } }
T System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>.this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } }
System.Numerics.Tensors.Tensor<T> System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>.this[params scoped System.ReadOnlySpan<System.Buffers.NRange> ranges] { get { throw null; } }
T System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>.this[params scoped System.ReadOnlySpan<nint> indexes] { get { throw null; } }
System.ReadOnlySpan<nint> System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>.Lengths { get { throw null; } }
System.ReadOnlySpan<nint> System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>.Strides { get { throw null; } }
bool System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>.IsReadOnly { get { throw null; } }
bool System.Numerics.Tensors.ITensor.IsReadOnly { get { throw null; } }
object System.Numerics.Tensors.ITensor.this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } set { } }
object System.Numerics.Tensors.ITensor.this[params scoped System.ReadOnlySpan<nint> indexes] { get { throw null; } set { } }
T System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>.this[params scoped System.ReadOnlySpan<System.Buffers.NIndex> indexes] { get { throw null; } set { } }
T System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>.this[params scoped System.ReadOnlySpan<nint> indexes] { get { throw null; } set { } }
public System.Numerics.Tensors.ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan() { throw null; }
Expand All @@ -849,12 +867,14 @@ internal Tensor() { }
public System.Numerics.Tensors.TensorSpan<T> AsTensorSpan(params scoped System.ReadOnlySpan<nint> start) { throw null; }
public void Clear() { }
public void CopyTo(scoped System.Numerics.Tensors.TensorSpan<T> destination) { }
public void Fill(object value) { }
public void Fill(T value) { }
public void FlattenTo(scoped System.Span<T> destination) { }
public System.Collections.Generic.IEnumerator<T> GetEnumerator() { throw null; }
public override int GetHashCode() { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public ref T GetPinnableReference() { throw null; }
public System.Buffers.MemoryHandle GetPinnedHandle() { throw null; }
public static implicit operator System.Numerics.Tensors.ReadOnlyTensorSpan<T> (System.Numerics.Tensors.Tensor<T> value) { throw null; }
public static implicit operator System.Numerics.Tensors.TensorSpan<T> (System.Numerics.Tensors.Tensor<T> value) { throw null; }
public static implicit operator System.Numerics.Tensors.Tensor<T> (T[] array) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,13 @@

namespace System.Numerics.Tensors
{

/// <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> : IEnumerable<T>
where TSelf : IReadOnlyTensor<TSelf, T>
public interface IReadOnlyTensor
{
/// <summary>
/// Gets an empty tensor.
/// </summary>
static abstract TSelf? Empty { get; }

/// <summary>
/// Gets a value that indicates whether the collection is currently empty.
/// </summary>
Expand All @@ -41,17 +34,62 @@ public interface IReadOnlyTensor<TSelf, T> : IEnumerable<T>
/// </summary>
int Rank { get; }

/// <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>
[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>
/// <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>
T this[params scoped ReadOnlySpan<nint> indexes] { get; }
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>
T this[params scoped ReadOnlySpan<NIndex> indexes] { get; }
new T this[params scoped ReadOnlySpan<NIndex> indexes] { get; }

/// <summary>
/// Gets the values at the specified ranges.
Expand Down Expand Up @@ -98,18 +136,6 @@ public interface IReadOnlyTensor<TSelf, T> : IEnumerable<T>
/// <param name="destination">The destination span where the data should be flattened to.</param>
void FlattenTo(scoped Span<T> destination);

/// <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>
[UnscopedRef]
ReadOnlySpan<nint> Strides { get; }

/// <summary>
/// Returns a reference to the 0th element of the tensor. If the tensor is empty, returns <see langword="null"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,47 @@

namespace System.Numerics.Tensors
{
/// <summary>
/// Represents a tensor.
/// </summary>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public interface ITensor : IReadOnlyTensor
{
/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to be used.</param>
new object this[params scoped ReadOnlySpan<nint> indexes] { get; set; }

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

/// <summary>
/// Gets a value that indicates whether the collection is read-only.
/// </summary>
bool IsReadOnly { get; }

/// <summary>
/// Clears the tensor.
/// </summary>
void Clear();

/// <summary>
/// Fills the contents of this tensor with the given value.
/// </summary>
void Fill(object value);
}

/// <summary>
/// Represents a 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 ITensor<TSelf, T>
: IReadOnlyTensor<TSelf, T>
public interface ITensor<TSelf, T> : ITensor, IReadOnlyTensor<TSelf, T>
where TSelf : ITensor<TSelf, T>
{
// TODO: Determine if we can implement `IEqualityOperators<TSelf, T, bool>`.
Expand Down Expand Up @@ -67,11 +100,6 @@ public interface ITensor<TSelf, T>
/// </remarks>
static abstract TSelf CreateUninitialized(scoped ReadOnlySpan<nint> lengths, scoped ReadOnlySpan<nint> strides, bool pinned = false);

/// <summary>
/// Gets a value that idicates whether the collection is read-only.
/// </summary>
bool IsReadOnly { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
Expand Down Expand Up @@ -117,11 +145,6 @@ public interface ITensor<TSelf, T>
/// <returns>The converted <see cref="TensorSpan{T}"/>.</returns>
TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<NRange> range);

/// <summary>
/// Clears the tensor.
/// </summary>
void Clear();

/// <summary>
/// Fills the contents of this tensor with the given value.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ namespace System.Numerics.Tensors
/// Represents a tensor.
/// </summary>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public sealed class Tensor<T>
: ITensor<Tensor<T>, T>
public sealed class Tensor<T> : ITensor, ITensor<Tensor<T>, T>
{
/// <summary>A byref or a native ptr.</summary>
internal readonly T[] _values;
Expand Down Expand Up @@ -176,7 +175,7 @@ static Tensor<T> ITensor<Tensor<T>, T>.CreateUninitialized(scoped ReadOnlySpan<n
/// Gets the length of each dimension in this <see cref="Tensor{T}"/>.
/// </summary>
/// <value><see cref="ReadOnlySpan{T}"/> with the lengths of each dimension.</value>
ReadOnlySpan<nint> IReadOnlyTensor<Tensor<T>, T>.Lengths => _lengths;
ReadOnlySpan<nint> IReadOnlyTensor.Lengths => _lengths;


/// <summary>
Expand All @@ -189,9 +188,16 @@ static Tensor<T> ITensor<Tensor<T>, T>.CreateUninitialized(scoped ReadOnlySpan<n
/// Gets the strides of each dimension in this <see cref="Tensor{T}"/>.
/// </summary>
/// <value><see cref="ReadOnlySpan{T}"/> with the strides of each dimension.</value>
ReadOnlySpan<nint> IReadOnlyTensor<Tensor<T>, T>.Strides => _strides;
ReadOnlySpan<nint> IReadOnlyTensor.Strides => _strides;

bool ITensor<Tensor<T>, T>.IsReadOnly => false;
bool ITensor.IsReadOnly => false;

object IReadOnlyTensor.this[params scoped ReadOnlySpan<NIndex> indexes] => this[indexes]!;

object IReadOnlyTensor.this[params scoped ReadOnlySpan<nint> indexes] => this[indexes]!;

object ITensor.this[params scoped ReadOnlySpan<NIndex> indexes] { get => this[indexes]!; set => this[indexes] = (T)value; }
object ITensor.this[params scoped ReadOnlySpan<nint> indexes] { get => this[indexes]!; set => this[indexes] = (T)value; }

/// <summary>
/// Returns a reference to specified element of the Tensor.
Expand Down Expand Up @@ -524,6 +530,11 @@ public Tensor<T> Slice(params ReadOnlySpan<NIndex> startIndex)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Fill(T value) => AsTensorSpan().Fill(value);

/// <summary>
/// Fills the contents of this span with the given value.
/// </summary>
public void Fill(object value) => Fill(value is T t ? t : throw new ArgumentException($"Cannot convert {value} to {typeof(T)}"));

/// <summary>
/// Copies the contents of this tensor into destination span. If the source
/// and destinations overlap, this method behaves as if the original values in
Expand Down Expand Up @@ -671,5 +682,18 @@ public string ToString(params ReadOnlySpan<nint> maximumLengths)
sb.AppendLine("}");
return sb.ToString();
}

/// <summary>
/// Pins and gets a <see cref="MemoryHandle"/> to the backing memory.
/// </summary>
/// <returns>A <see cref="MemoryHandle"/> which has pinned the backing memory.</returns>
public MemoryHandle GetPinnedHandle()
{
GCHandle handle = GCHandle.Alloc(_values, GCHandleType.Pinned);
unsafe
{
return new MemoryHandle(Unsafe.AsPointer(ref GetPinnableReference()), handle);
}
}
}
}
Loading
Loading