Skip to content

Commit

Permalink
IROTensor,ITensor,Tensor API updates
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelgsharp committed May 13, 2024
1 parent 7435fb7 commit dfc0745
Show file tree
Hide file tree
Showing 11 changed files with 537 additions and 181 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<Compile Include="System\Numerics\Tensors\netcore\Common\IReadOnlyTensor.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" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.Numerics.Tensors
{
public interface IReadOnlyTensor<TSelf, T> : IEnumerable<T>
where TSelf : IReadOnlyTensor<TSelf, T>
{
static abstract TSelf? Empty { get; }

bool IsEmpty { get; }
bool IsPinned { get; }
nint FlattenedLength { get; }
int Rank { get; }

T this[params ReadOnlySpan<nint> indexes] { get; }
T this[params ReadOnlySpan<NIndex> indexes] { get; }
TSelf this[params scoped ReadOnlySpan<NRange> ranges] { get; }

ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan();
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<nint> start);
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<NIndex> startIndex);
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<NRange> range);

void CopyTo(TensorSpan<T> destination);
void FlattenTo(Span<T> destination);

// These are not properties so that structs can implement the interface without allocating:
void GetLengths(Span<nint> destination);
void GetStrides(Span<nint> destination);

ref readonly T GetPinnableReference();
TSelf Slice(params scoped ReadOnlySpan<nint> start);
TSelf Slice(params scoped ReadOnlySpan<NIndex> startIndex);
TSelf Slice(params scoped ReadOnlySpan<NRange> range);
bool TryCopyTo(TensorSpan<T> destination);
bool TryFlattenTo(Span<T> destination);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,32 @@
namespace System.Numerics.Tensors
{
public interface ITensor<TSelf, T>
: IEnumerable<T>
: IReadOnlyTensor<TSelf, T>
where TSelf : ITensor<TSelf, T>
{
// TODO: Determine if we can implement `IEqualityOperators<TSelf, T, bool>`.
// It looks like C#/.NET currently hits limitations here as it believes TSelf and T could be the same type
// Ideally we could annotate it such that they cannot be the same type and no conflicts would exist

static abstract TSelf? Empty { get; }
static abstract TSelf Create(ReadOnlySpan<nint> lengths, bool pinned = false);
static abstract TSelf Create(ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides, bool pinned = false);

bool IsEmpty { get; }
bool IsPinned { get; }
int Rank { get; }
nint FlattenedLength { get; }
// THIS IS GOING TO PEND A DISCUSSION WITH THE LANGUAGE TEAM
void GetStrides(Span<nint> destination);
void GetLengths(Span<nint> destination);
static abstract TSelf CreateUninitialized(ReadOnlySpan<nint> lengths, bool pinned = false);
static abstract TSelf CreateUninitialized(ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides, bool pinned = false);

T this[params scoped ReadOnlySpan<nint> indexes] { get; }
T this[params scoped ReadOnlySpan<NIndex> indexes] { get; set; }
TSelf this[params scoped ReadOnlySpan<NRange> ranges] { get; set; }
bool IsReadOnly { get; }

TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<NRange> ranges);
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<NRange> ranges);
ref T GetPinnableReference();
TSelf Slice(params scoped ReadOnlySpan<NRange> ranges);
new T this[params ReadOnlySpan<nint> indexes] { get; set; }
new T this[params ReadOnlySpan<NIndex> indexes] { get; set; }
new TSelf this[params scoped ReadOnlySpan<NRange> ranges] { get; set; }

TensorSpan<T> AsTensorSpan();
TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<nint> start);
TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<NIndex> startIndex);
TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<NRange> range);

void Clear();
void CopyTo(TensorSpan<T> destination);
void Fill(T value);
bool TryCopyTo(TensorSpan<T> destination);
new ref T GetPinnableReference();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public ReadOnlyTensorSpan(T[]? array) : this(array, 0, default, default)
/// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="startIndex"/> or end index is not in the range (&lt;0 or &gt;Length).
/// Thrown when the specified <paramref name="startIndex"/> or end index is not in the range (&lt;0 or &gt;FlattenedLength).
/// </exception>
public ReadOnlyTensorSpan(T[]? array, Index startIndex, ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides)
: this(array, startIndex.GetOffset(array?.Length ?? 0), lengths, strides)
Expand All @@ -74,7 +74,7 @@ public ReadOnlyTensorSpan(T[]? array, Index startIndex, ReadOnlySpan<nint> lengt
/// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;Length).
/// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;FlattenedLength).
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlyTensorSpan(T[]? array, int start, ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides)
Expand Down Expand Up @@ -205,7 +205,7 @@ internal ReadOnlyTensorSpan(ref T reference, scoped ReadOnlySpan<nint> lengths,
/// <param name="indexes"></param>
/// <returns></returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when any index is less than 0 or any index is greater than or equal to Length
/// Thrown when any index is less than 0 or any index is greater than or equal to FlattenedLength
/// </exception>
public ref readonly T this[params scoped ReadOnlySpan<nint> indexes]
{
Expand All @@ -229,7 +229,7 @@ public ref readonly T this[params scoped ReadOnlySpan<nint> indexes]
/// <param name="indexes"></param>
/// <returns></returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when any index is less than 0 or any index is greater than or equal to Length
/// Thrown when any index is less than 0 or any index is greater than or equal to FlattenedLength
/// </exception>
public ref readonly T this[params scoped ReadOnlySpan<NIndex> indexes]
{
Expand All @@ -252,7 +252,7 @@ public ref readonly T this[params scoped ReadOnlySpan<NIndex> indexes]
/// <param name="ranges"></param>
/// <returns></returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when any index is less than 0 or any index is greater than or equal to Length
/// Thrown when any index is less than 0 or any index is greater than or equal to FlattenedLength
/// </exception>
public ReadOnlyTensorSpan<T> this[params scoped ReadOnlySpan<NRange> ranges]
{
Expand Down Expand Up @@ -515,7 +515,7 @@ public bool TryCopyTo(TensorSpan<T> destination)
/// <param name="indexes">The indexes for the slice.</param>
/// <returns></returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when any index is less than 0 or any index is greater than or equal to Length
/// Thrown when any index is less than 0 or any index is greater than or equal to FlattenedLength
/// </exception>
public ReadOnlyTensorSpan<T> Slice(params scoped ReadOnlySpan<NIndex> indexes)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ namespace System.Numerics.Tensors
public static partial class Tensor
{
/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with the default value of T. If <paramref name="mustPin"/> is true, the memory will be pinned.
/// Creates a <see cref="Tensor{T}"/> and initializes it with the default value of T. If <paramref name="pinned"/> is true, the memory will be pinned.
/// </summary>
/// <param name="mustPin">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
public static Tensor<T> Create<T>(bool mustPin, ReadOnlySpan<nint> lengths)
/// <param name="pinned">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
public static Tensor<T> Create<T>(ReadOnlySpan<nint> lengths, bool pinned = false)
where T : IEquatable<T>
{
nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths);
T[] values = mustPin ? GC.AllocateArray<T>((int)linearLength, mustPin) : (new T[linearLength]);
return new Tensor<T>(values, lengths.ToArray(), mustPin);
T[] values = pinned ? GC.AllocateArray<T>((int)linearLength, pinned) : (new T[linearLength]);
return new Tensor<T>(values, lengths.ToArray(), pinned);
}

/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with the default value of T. If <paramref name="mustPin"/> is true, the memory will be pinned.
/// Creates a <see cref="Tensor{T}"/> and initializes it with the default value of T. If <paramref name="pinned"/> is true, the memory will be pinned.
/// </summary>
/// <param name="mustPin">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
/// <param name="strides">A <see cref="ReadOnlySpan{T}"/> indicating the strides of each dimension.</param>
public static Tensor<T> Create<T>(bool mustPin, ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides)
/// <param name="pinned">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
public static Tensor<T> Create<T>(ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides, bool pinned = false)
where T : IEquatable<T>
{
nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths);
T[] values = mustPin ? GC.AllocateArray<T>((int)linearLength, mustPin) : (new T[linearLength]);
return new Tensor<T>(values, lengths.ToArray(), strides.ToArray(), mustPin);
T[] values = pinned ? GC.AllocateArray<T>((int)linearLength, pinned) : (new T[linearLength]);
return new Tensor<T>(values, lengths.ToArray(), strides.ToArray(), pinned);
}

/// <summary>
Expand Down Expand Up @@ -75,30 +75,30 @@ public static Tensor<T> Create<T>(T[] values, ReadOnlySpan<nint> lengths, ReadOn
}

/// <summary>
/// Creates a <see cref="Tensor{T}"/> and does not initialize it. If <paramref name="mustPin"/> is true, the memory will be pinned.
/// Creates a <see cref="Tensor{T}"/> and does not initialize it. If <paramref name="pinned"/> is true, the memory will be pinned.
/// </summary>
/// <param name="mustPin">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
public static Tensor<T> CreateUninitialized<T>(bool mustPin, ReadOnlySpan<nint> lengths)
/// <param name="pinned">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
public static Tensor<T> CreateUninitialized<T>(ReadOnlySpan<nint> lengths, bool pinned = false)
where T : IEquatable<T>
{
nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths);
T[] values = GC.AllocateUninitializedArray<T>((int)linearLength, mustPin);
return new Tensor<T>(values, lengths.ToArray(), mustPin);
T[] values = GC.AllocateUninitializedArray<T>((int)linearLength, pinned);
return new Tensor<T>(values, lengths.ToArray(), pinned);
}

/// <summary>
/// Creates a <see cref="Tensor{T}"/> and does not initialize it. If <paramref name="mustPin"/> is true, the memory will be pinned.
/// Creates a <see cref="Tensor{T}"/> and does not initialize it. If <paramref name="pinned"/> is true, the memory will be pinned.
/// </summary>
/// <param name="mustPin">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
/// <param name="strides">A <see cref="ReadOnlySpan{T}"/> indicating the strides of each dimension.</param>
public static Tensor<T> CreateUninitialized<T>(bool mustPin, ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides)
/// <param name="pinned">A <see cref="bool"/> whether the underlying data should be pinned or not.</param>
public static Tensor<T> CreateUninitialized<T>(ReadOnlySpan<nint> lengths, ReadOnlySpan<nint> strides, bool pinned = false )
where T : IEquatable<T>
{
nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths);
T[] values = GC.AllocateUninitializedArray<T>((int)linearLength, mustPin);
return new Tensor<T>(values, lengths.ToArray(), strides.ToArray(), mustPin);
T[] values = GC.AllocateUninitializedArray<T>((int)linearLength, pinned);
return new Tensor<T>(values, lengths.ToArray(), strides.ToArray(), pinned);
}

/// <summary>
Expand Down
Loading

0 comments on commit dfc0745

Please sign in to comment.