Skip to content

Commit

Permalink
Adding a naive implementation of various primitive tensor operations (d…
Browse files Browse the repository at this point in the history
…otnet#91228)

* Adding a naive implementation of various primitive tensor operations

* Adding tests covering the new tensor primitives APIs

* Adding tensor primitives APIs to the ref assembly

* Allow .NET Framework to build/run

* Sync TFMs between ref and src, csproj simplication and clean-up

* Apply suggestions from code review

Co-authored-by: Viktor Hofer <viktor.hofer@microsoft.com>

* Don't use var

* Fix the S.N.Tensors readme and remove the file marking it as non-shipping

---------

Co-authored-by: Viktor Hofer <viktor.hofer@microsoft.com>
Co-authored-by: Michael Sharp <51342856+michaelgsharp@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 5, 2023
1 parent 413be50 commit 85259f6
Show file tree
Hide file tree
Showing 26 changed files with 1,181 additions and 23,373 deletions.
8 changes: 0 additions & 8 deletions src/libraries/System.Numerics.Tensors/Directory.Build.props

This file was deleted.

3 changes: 2 additions & 1 deletion src/libraries/System.Numerics.Tensors/README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# System.Numerics.Tensors
This library has not been shipped publicly and is not accepting contributions at this time.

Provides APIs for performing primitive operations over tensors represented by spans of memory.
166 changes: 21 additions & 145 deletions src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,151 +6,27 @@

namespace System.Numerics.Tensors
{
public static partial class ArrayTensorExtensions
public static class TensorPrimitives
{
public static System.Numerics.Tensors.CompressedSparseTensor<T> ToCompressedSparseTensor<T>(this System.Array array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.CompressedSparseTensor<T> ToCompressedSparseTensor<T>(this T[,,] array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.CompressedSparseTensor<T> ToCompressedSparseTensor<T>(this T[,] array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.CompressedSparseTensor<T> ToCompressedSparseTensor<T>(this T[] array) { throw null; }
public static System.Numerics.Tensors.SparseTensor<T> ToSparseTensor<T>(this System.Array array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.SparseTensor<T> ToSparseTensor<T>(this T[,,] array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.SparseTensor<T> ToSparseTensor<T>(this T[,] array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.SparseTensor<T> ToSparseTensor<T>(this T[] array) { throw null; }
public static System.Numerics.Tensors.DenseTensor<T> ToTensor<T>(this System.Array array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.DenseTensor<T> ToTensor<T>(this T[,,] array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.DenseTensor<T> ToTensor<T>(this T[,] array, bool reverseStride = false) { throw null; }
public static System.Numerics.Tensors.DenseTensor<T> ToTensor<T>(this T[] array) { throw null; }
}
public partial class CompressedSparseTensor<T> : System.Numerics.Tensors.Tensor<T>
{
public CompressedSparseTensor(System.Memory<T> values, System.Memory<int> compressedCounts, System.Memory<int> indices, int nonZeroCount, System.ReadOnlySpan<int> dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { }
public CompressedSparseTensor(System.ReadOnlySpan<int> dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { }
public CompressedSparseTensor(System.ReadOnlySpan<int> dimensions, int capacity, bool reverseStride = false) : base (default(System.Array), default(bool)) { }
public int Capacity { get { throw null; } }
public System.Memory<int> CompressedCounts { get { throw null; } }
public System.Memory<int> Indices { get { throw null; } }
public override T this[System.ReadOnlySpan<int> indices] { get { throw null; } set { } }
public int NonZeroCount { get { throw null; } }
public System.Memory<T> Values { get { throw null; } }
public override System.Numerics.Tensors.Tensor<T> Clone() { throw null; }
public override System.Numerics.Tensors.Tensor<TResult> CloneEmpty<TResult>(System.ReadOnlySpan<int> dimensions) { throw null; }
public override T GetValue(int index) { throw null; }
public override System.Numerics.Tensors.Tensor<T> Reshape(System.ReadOnlySpan<int> dimensions) { throw null; }
public override void SetValue(int index, T value) { }
public override System.Numerics.Tensors.CompressedSparseTensor<T> ToCompressedSparseTensor() { throw null; }
public override System.Numerics.Tensors.DenseTensor<T> ToDenseTensor() { throw null; }
public override System.Numerics.Tensors.SparseTensor<T> ToSparseTensor() { throw null; }
}
public partial class DenseTensor<T> : System.Numerics.Tensors.Tensor<T>
{
public DenseTensor(int length) : base (default(System.Array), default(bool)) { }
public DenseTensor(System.Memory<T> memory, System.ReadOnlySpan<int> dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { }
public DenseTensor(System.ReadOnlySpan<int> dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { }
public System.Memory<T> Buffer { get { throw null; } }
public override System.Numerics.Tensors.Tensor<T> Clone() { throw null; }
public override System.Numerics.Tensors.Tensor<TResult> CloneEmpty<TResult>(System.ReadOnlySpan<int> dimensions) { throw null; }
protected override void CopyTo(T[] array, int arrayIndex) { }
public override T GetValue(int index) { throw null; }
protected override int IndexOf(T item) { throw null; }
public override System.Numerics.Tensors.Tensor<T> Reshape(System.ReadOnlySpan<int> dimensions) { throw null; }
public override void SetValue(int index, T value) { }
}
public partial class SparseTensor<T> : System.Numerics.Tensors.Tensor<T>
{
public SparseTensor(System.ReadOnlySpan<int> dimensions, bool reverseStride = false, int capacity = 0) : base (default(System.Array), default(bool)) { }
public int NonZeroCount { get { throw null; } }
public override System.Numerics.Tensors.Tensor<T> Clone() { throw null; }
public override System.Numerics.Tensors.Tensor<TResult> CloneEmpty<TResult>(System.ReadOnlySpan<int> dimensions) { throw null; }
public override T GetValue(int index) { throw null; }
public override System.Numerics.Tensors.Tensor<T> Reshape(System.ReadOnlySpan<int> dimensions) { throw null; }
public override void SetValue(int index, T value) { }
public override System.Numerics.Tensors.CompressedSparseTensor<T> ToCompressedSparseTensor() { throw null; }
public override System.Numerics.Tensors.DenseTensor<T> ToDenseTensor() { throw null; }
public override System.Numerics.Tensors.SparseTensor<T> ToSparseTensor() { throw null; }
}
public static partial class Tensor
{
public static System.Numerics.Tensors.Tensor<T> CreateFromDiagonal<T>(System.Numerics.Tensors.Tensor<T> diagonal) { throw null; }
public static System.Numerics.Tensors.Tensor<T> CreateFromDiagonal<T>(System.Numerics.Tensors.Tensor<T> diagonal, int offset) { throw null; }
public static System.Numerics.Tensors.Tensor<T> CreateIdentity<T>(int size) { throw null; }
public static System.Numerics.Tensors.Tensor<T> CreateIdentity<T>(int size, bool columMajor) { throw null; }
public static System.Numerics.Tensors.Tensor<T> CreateIdentity<T>(int size, bool columMajor, T oneValue) { throw null; }
}
public abstract partial class Tensor<T> : System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable
{
protected Tensor(System.Array fromArray, bool reverseStride) { }
protected Tensor(int length) { }
protected Tensor(System.ReadOnlySpan<int> dimensions, bool reverseStride) { }
public System.ReadOnlySpan<int> Dimensions { get { throw null; } }
public bool IsFixedSize { get { throw null; } }
public bool IsReadOnly { get { throw null; } }
public bool IsReversedStride { get { throw null; } }
public virtual T this[params int[] indices] { get { throw null; } set { } }
public virtual T this[System.ReadOnlySpan<int> indices] { get { throw null; } set { } }
public long Length { get { throw null; } }
public int Rank { get { throw null; } }
public System.ReadOnlySpan<int> Strides { get { throw null; } }
int System.Collections.Generic.ICollection<T>.Count { get { throw null; } }
T System.Collections.Generic.IList<T>.this[int index] { get { throw null; } set { } }
int System.Collections.Generic.IReadOnlyCollection<T>.Count { get { throw null; } }
T System.Collections.Generic.IReadOnlyList<T>.this[int index] { get { throw null; } }
int System.Collections.ICollection.Count { get { throw null; } }
bool System.Collections.ICollection.IsSynchronized { get { throw null; } }
object System.Collections.ICollection.SyncRoot { get { throw null; } }
object? System.Collections.IList.this[int index] { get { throw null; } set { } }
public abstract System.Numerics.Tensors.Tensor<T> Clone();
public virtual System.Numerics.Tensors.Tensor<T> CloneEmpty() { throw null; }
public virtual System.Numerics.Tensors.Tensor<T> CloneEmpty(System.ReadOnlySpan<int> dimensions) { throw null; }
public virtual System.Numerics.Tensors.Tensor<TResult> CloneEmpty<TResult>() { throw null; }
public abstract System.Numerics.Tensors.Tensor<TResult> CloneEmpty<TResult>(System.ReadOnlySpan<int> dimensions);
public static int Compare(System.Numerics.Tensors.Tensor<T> left, System.Numerics.Tensors.Tensor<T> right) { throw null; }
protected virtual bool Contains(T item) { throw null; }
protected virtual void CopyTo(T[] array, int arrayIndex) { }
public static bool Equals(System.Numerics.Tensors.Tensor<T> left, System.Numerics.Tensors.Tensor<T> right) { throw null; }
public virtual void Fill(T value) { }
public string GetArrayString(bool includeWhitespace = true) { throw null; }
public System.Numerics.Tensors.Tensor<T> GetDiagonal() { throw null; }
public System.Numerics.Tensors.Tensor<T> GetDiagonal(int offset) { throw null; }
public System.Numerics.Tensors.Tensor<T> GetTriangle() { throw null; }
public System.Numerics.Tensors.Tensor<T> GetTriangle(int offset) { throw null; }
public System.Numerics.Tensors.Tensor<T> GetUpperTriangle() { throw null; }
public System.Numerics.Tensors.Tensor<T> GetUpperTriangle(int offset) { throw null; }
public abstract T GetValue(int index);
protected virtual int IndexOf(T item) { throw null; }
public abstract System.Numerics.Tensors.Tensor<T> Reshape(System.ReadOnlySpan<int> dimensions);
public abstract void SetValue(int index, T value);
public struct Enumerator : System.Collections.Generic.IEnumerator<T>
{
public T Current { get; private set; }
object? System.Collections.IEnumerator.Current => throw null;
public bool MoveNext() => throw null;
public void Reset() { }
public void Dispose() { }
}
public Enumerator GetEnumerator() => throw null;
void System.Collections.Generic.ICollection<T>.Add(T item) { }
void System.Collections.Generic.ICollection<T>.Clear() { }
bool System.Collections.Generic.ICollection<T>.Contains(T item) { throw null; }
void System.Collections.Generic.ICollection<T>.CopyTo(T[] array, int arrayIndex) { }
bool System.Collections.Generic.ICollection<T>.Remove(T item) { throw null; }
System.Collections.Generic.IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator() { throw null; }
int System.Collections.Generic.IList<T>.IndexOf(T item) { throw null; }
void System.Collections.Generic.IList<T>.Insert(int index, T item) { }
void System.Collections.Generic.IList<T>.RemoveAt(int index) { }
void System.Collections.ICollection.CopyTo(System.Array array, int index) { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
int System.Collections.IList.Add(object? value) { throw null; }
void System.Collections.IList.Clear() { }
bool System.Collections.IList.Contains(object? value) { throw null; }
int System.Collections.IList.IndexOf(object? value) { throw null; }
void System.Collections.IList.Insert(int index, object? value) { }
void System.Collections.IList.Remove(object? value) { }
void System.Collections.IList.RemoveAt(int index) { }
int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; }
bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; }
int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; }
public virtual System.Numerics.Tensors.CompressedSparseTensor<T> ToCompressedSparseTensor() { throw null; }
public virtual System.Numerics.Tensors.DenseTensor<T> ToDenseTensor() { throw null; }
public virtual System.Numerics.Tensors.SparseTensor<T> ToSparseTensor() { throw null; }
public static void Add(System.ReadOnlySpan<float> x, float y, System.Span<float> destination) { throw null; }
public static void Add(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, System.Span<float> destination) { throw null; }
public static void AddMultiply(System.ReadOnlySpan<float> x, float y, System.ReadOnlySpan<float> multiplier, System.Span<float> destination) { throw null; }
public static void AddMultiply(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, float multiplier, System.Span<float> destination) { throw null; }
public static void AddMultiply(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, System.ReadOnlySpan<float> multiplier, System.Span<float> destination) { throw null; }
public static void Cosh(System.ReadOnlySpan<float> x, System.Span<float> destination) { throw null; }
public static void Divide(System.ReadOnlySpan<float> x, float y, System.Span<float> destination) { throw null; }
public static void Divide(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, System.Span<float> destination) { throw null; }
public static void Exp(System.ReadOnlySpan<float> x, System.Span<float> destination) { throw null; }
public static void Log(System.ReadOnlySpan<float> x, System.Span<float> destination) { throw null; }
public static void Multiply(System.ReadOnlySpan<float> x, float y, System.Span<float> destination) { throw null; }
public static void Multiply(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, System.Span<float> destination) { throw null; }
public static void MultiplyAdd(System.ReadOnlySpan<float> x, float y, System.ReadOnlySpan<float> addend, System.Span<float> destination) { throw null; }
public static void MultiplyAdd(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, float addend, System.Span<float> destination) { throw null; }
public static void MultiplyAdd(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, System.ReadOnlySpan<float> addend, System.Span<float> destination) { throw null; }
public static void Negate(System.ReadOnlySpan<float> x, System.Span<float> destination) { throw null; }
public static void Subtract(System.ReadOnlySpan<float> x, float y, System.Span<float> destination) { throw null; }
public static void Subtract(System.ReadOnlySpan<float> x, System.ReadOnlySpan<float> y, System.Span<float> destination) { throw null; }
public static void Sinh(System.ReadOnlySpan<float> x, System.Span<float> destination) { throw null; }
public static void Tanh(System.ReadOnlySpan<float> x, System.Span<float> destination) { throw null; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
</PropertyGroup>
Expand All @@ -10,4 +11,5 @@
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<PackageReference Include="System.Memory" Version="$(SystemMemoryVersion)" />
</ItemGroup>

</Project>

This file was deleted.

50 changes: 4 additions & 46 deletions src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -117,52 +117,10 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArrayMustContainElements" xml:space="preserve">
<value>Array must contain elements.</value>
<data name="Argument_DestinationTooShort" xml:space="preserve">
<value>Destination is too short.</value>
</data>
<data name="CannotCompare" xml:space="preserve">
<value>Cannot compare {0} to {1}.</value>
</data>
<data name="CannotCompareToWithDifferentDimension" xml:space="preserve">
<value>Cannot compare {0} to {1} with different dimension {2}, {3} != {4}.</value>
</data>
<data name="CannotCompareWithDifferentDimension" xml:space="preserve">
<value>Cannot compare {0} with different dimension {1}, {2} != {3}.</value>
</data>
<data name="CannotCompareWithRank" xml:space="preserve">
<value>Cannot compare {0} with Rank {1} to {2} with Rank {3}.</value>
</data>
<data name="CannotComputeDiagonal" xml:space="preserve">
<value>Cannot compute diagonal of {0} with Rank less than 2.</value>
</data>
<data name="CannotComputeDiagonalWithOffset" xml:space="preserve">
<value>Cannot compute diagonal with offset {0}.</value>
</data>
<data name="MustHaveAtLeastOneDimension" xml:space="preserve">
<value>Tensor {0} must have at least one dimension.</value>
</data>
<data name="CannotComputeTriangle" xml:space="preserve">
<value>Cannot compute triangle of {0} with Rank less than 2.</value>
</data>
<data name="CannotReshapeArrayDueToMismatchInLengths" xml:space="preserve">
<value>Cannot reshape array due to mismatch in lengths, currently {0} would become {1}.</value>
</data>
<data name="DimensionsMustBePositiveAndNonZero" xml:space="preserve">
<value>Dimensions must be positive and non-zero.</value>
</data>
<data name="DimensionsMustContainElements" xml:space="preserve">
<value>Dimensions must contain elements.</value>
</data>
<data name="LengthMustMatch" xml:space="preserve">
<value>Length of {0} ({1}) must match product of {2} ({3}).</value>
</data>
<data name="NumberGreaterThenAvailableSpace" xml:space="preserve">
<value>The number of elements in the Tensor is greater than the available space from index to the end of the destination array.</value>
</data>
<data name="OnlySingleDimensionalArraysSupported" xml:space="preserve">
<value>Only single dimensional arrays are supported for the requested action.</value>
</data>
<data name="ValueIsNotOfType" xml:space="preserve">
<value>The value "{0}" is not of type "{1}" and cannot be used in this generic collection.</value>
<data name="Argument_SpansMustHaveSameLength" xml:space="preserve">
<value>Length of '{0}' must be same as length of '{1}'.</value>
</data>
</root>
Loading

0 comments on commit 85259f6

Please sign in to comment.