Open
Description
This is a continuation of #103611 and covers the various operation like APIs that do meaningful work with Tensor<T>
and supporting types.
API Proposal -- New APIs for Tensor, TensorSpan, and TensorPrimitives
namespace System.Numerics.Tensors;
public static partial class Tensor
{
public static T Mean<T>(in ROTensorSpan<T> x) where T : IFloatingPoint<T>;
// The following APIs could have Tensor<bool> and bool versions,
// following the `*()`, `*All()` and `*Any()` pattern:
//
// IBinaryNumber
// * IsPow2
// INumberBase
// * IsCanonical
// * IsComplexNumber
// * IsEvenInteger
// * IsFinite
// * IsImaginaryNumber
// * IsInfinity
// * IsInteger
// * IsNaN
// * IsNegative
// * IsNegativeInfinity
// * IsNormal
// * IsOddInteger
// * IsPositive
// * IsPositiveInfinity
// * IsRealNumber
// * IsSubnormal
// * IsZero
}
public static partial class TensorPrimitives
{
public static T Mean<T>(ROSpan<T> x) where T : IFloatingPoint<T>;
// The following APIs could have Tensor<bool> and bool versions,
// following the `*()`, `*All()` and `*Any()` pattern:
//
// IBinaryNumber
// * IsPow2
// INumberBase
// * IsCanonical
// * IsComplexNumber
// * IsEvenInteger
// * IsFinite
// * IsImaginaryNumber
// * IsInfinity
// * IsInteger
// * IsNaN
// * IsNegative
// * IsNegativeInfinity
// * IsNormal
// * IsOddInteger
// * IsPositive
// * IsPositiveInfinity
// * IsRealNumber
// * IsSubnormal
// * IsZero
}
API Proposal -- APIs unique to Tensor and TensorSpan
These cover APIs that do not have an equivalent in TensorPrimitives
, typically being functionality that is unique to multi-dimensional types:
namespace System.Numerics.Tensors;
public static partial class Tensor
{
public static ROTensorSpan<T> AsROTensorSpan<T>(this T[]? array, params scoped ROSpan<nint> lengths);
public static TensorSpan<T> AsTensorSpan<T>(this T[]? array, params scoped ROSpan<nint> lengths);
public static Tensor<T> Broadcast<T>(in ROTensorSpan<T> x, ROSpan<nint> lengths);
// This gets the lengths from lengthsSource
public static Tensor<T> Broadcast<T>(in ROTensorSpan<T> x, in ROTensorSpan<T> lengthsSource);
public static void BroadcastTo<T>(this Tensor<T> x, in TensorSpan<T> destination);
public static void BroadcastTo<T>(in this TensorSpan<T> x, in TensorSpan<T> destination);
public static void BroadcastTo<T>(in this ROTensorSpan<T> x, in TensorSpan<T> destination);
// The parameter order here feels off. Ideally tensors could be params
// and we'd have overloads taking 2-3x ROTensorSpan<T>. Maybe we can
// explode the overloads a bit to make this nicer?
public static Tensor<T> Concatenate<T>(ROSpan<Tensor<T>> tensors, int axis = 0);
public static TensorSpan<T> Concatenate<T>(scoped ROSpan<Tensor<T>> tensors, in TensorSpan<T> destination, int axis = 0);
public static Tensor<T> Create<T>(ROSpan<nint> lengths, bool pinned = false);
public static Tensor<T> Create<T>(ROSpan<nint> lengths, ROSpan<nint> strides, bool pinned = false);
public static Tensor<T> Create<T>(T[] values, ROSpan<nint> lengths);
public static Tensor<T> Create<T>(T[] values, ROSpan<nint> lengths, ROSpan<nint> strides, bool isPinned = false);
public static Tensor<T> Create<T>(IEnumerable<T> values, ROSpan<nint> lengths);
public static Tensor<T> Create<T>(IEnumerable<T> values, ROSpan<nint> lengths, ROSpan<nint> strides, bool isPinned = false);
public static Tensor<T> CreateAndFillGaussianNormalDistribution<T>(params ROSpan<nint> lengths) where T : IFloatingPoint<T>;
public static Tensor<T> CreateAndFillUniformDistribution<T>(params ROSpan<nint> lengths) where T : IFloatingPoint<T>;
public static Tensor<T> CreateUninitialized<T>(ROSpan<nint> lengths, bool pinned = false);
public static Tensor<T> CreateUninitialized<T>(ROSpan<nint> lengths, ROSpan<nint> strides, bool pinned = false);
public static TensorSpan<T> FillGaussianNormalDistribution<T>(in TensorSpan<T> destination) where T : IFloatingPoint<T>;
public static TensorSpan<T> FillUniformDistribution<T>(in TensorSpan<T> destination) where T : IFloatingPoint<T>;
// Should this be some overload of SetSlice or similar?
public static TensorSpan<T> FilteredUpdate<T>(in this TensorSpan<T> x, scoped in ROTensorSpan<bool> filter, scoped in ROTensorSpan<T> values);
public static TensorSpan<T> FilteredUpdate<T>(in this TensorSpan<T> x, scoped in ROTensorSpan<bool> filter, T value);
// Change order of the stride parameters
public static Tensor<T> Permute<T>(this Tensor<T> x, params ROSpan<int> axis);
public static TensorSpan<T> Permute<T>(in this TensorSpan<T> x, params scoped ROSpan<int> axis);
public static ROTensorSpan<T> Permute<T>(in this ROTensorSpan<T> x, params scoped ROSpan<int> axis);
// Change the lengths
public static Tensor<T> Reshape<T>(this Tensor<T> x, params ROSpan<nint> lengths);
public static TensorSpan<T> Reshape<T>(in this TensorSpan<T> x, params scoped ROSpan<nint> lengths);
public static ROTensorSpan<T> Reshape<T>(in this ROTensorSpan<T> x, params scoped ROSpan<nint> lengths);
public static Tensor<T> Resize<T>(Tensor<T> x, ROSpan<nint> lengths);
public static void ResizeTo<T>(this Tensor<T> x, in TensorSpan<nint> destination);
public static void ResizeTo<T>(in this TensorSpan<T> x, in TensorSpan<nint> destination);
public static void ResizeTo<T>(in this ROTensorSpan<T> x, in TensorSpan<nint> destination);
// Should this be expanded to avoid the optional axis parameter?
public static Tensor<T> Reverse<T>(in ROTensorSpan<T> x, nint axis = -1);
public static TensorSpan<T> Reverse<T>(scoped in ROTensorSpan<T> x, in TensorSpan<T> destination, nint axis = -1);
// These are distinct from EqualsAll in that they use IEquatable
public static bool SequenceEqual<T>(this in ROTensorSpan<T> span, in ROTensorSpan<T> other) where T : IEquatable<T>?;
public static bool SequenceEqual<T>(this in TensorSpan<T> span, in ROTensorSpan<T> other) where T : IEquatable<T>?;
// The ordering of these parameters is slightly backwards so params can work for the ranges
public static Tensor<T> SetSlice<T>(this Tensor<T> tensor, in ROTensorSpan<T> values, params ROSpan<NRange> ranges);
public static TensorSpan<T> SetSlice<T>(this TensorSpan<T> tensor, scoped in ROTensorSpan<T> values, params scoped ROSpan<NRange> ranges);
public static Tensor<T>[] Split<T>(in ROTensorSpan<T> x, nint numSplits, nint axis);
// Remove dimensions of length 1
public static Tensor<T> Squeeze<T>(this Tensor<T> x, int axis = -1);
public static TensorSpan<T> Squeeze<T>(in this TensorSpan<T> x, int axis = -1);
public static ROTensorSpan<T> Squeeze<T>(in this ROTensorSpan<T> x, int axis = -1);
public static Tensor<T> Stack<T>(ROSpan<Tensor<T>> tensors, int axis = 0);
public static TensorSpan<T> Stack<T>(scoped ROSpan<Tensor<T>> tensors, in TensorSpan<T> destination, int axis = 0);
public static string ToString<T>(in this ROTensorSpan<T> span, params ROSpan<nint> maximumLengths);
public static string ToString<T>(in this TensorSpan<T> span, params ROSpan<nint> maximumLengths);
public static Tensor<T> Transpose<T>(in ROTensorSpan<T> x);
public static TensorSpan<T> Transpose<T>(scoped in ROTensorSpan<T> x, in TensorSpan<T> destination);
public static bool TryBroadcastTo<T>(this Tensor<T> x, in TensorSpan<T> destination);
public static bool TryBroadcastTo<T>(in this TensorSpan<T> x, in TensorSpan<T> destination);
public static bool TryBroadcastTo<T>(in this ROTensorSpan<T> x, in TensorSpan<T> destination);
// Adds dimension of length 1
public static Tensor<T> Unsqueeze<T>(this Tensor<T> x, int axis);
public static TensorSpan<T> Unsqueeze<T>(in this TensorSpan<T> x, int axis);
public static ROTensorSpan<T> Unsqueeze<T>(in this ROTensorSpan<T> x, int axis);
}