From 74a74d575793e980c26416b85b657736e196f6e0 Mon Sep 17 00:00:00 2001 From: Michael Sharp Date: Mon, 3 Jun 2024 03:20:08 -0600 Subject: [PATCH 1/5] Additional validations and TensorPrimitives forwarding --- .../src/Resources/Strings.resx | 6 + .../src/System.Numerics.Tensors.csproj | 4 +- .../netcore/{Common => }/IReadOnlyTensor.cs | 8 +- .../Numerics/Tensors/netcore/ITensor.cs | 9 +- .../Tensors/netcore/ReadOnlyTensorSpan.cs | 94 +- .../Tensors/netcore/Tensor.Factory.cs | 31 +- .../System/Numerics/Tensors/netcore/Tensor.cs | 61 +- .../Tensors/netcore/TensorExtensions.cs | 2306 +++++++++++------ .../Numerics/Tensors/netcore/TensorHelpers.cs | 12 - .../TensorPrimitives.DegreesToRadians.cs | 2 +- .../Tensors/netcore/TensorPrimitives.Hypot.cs | 2 +- .../Numerics/Tensors/netcore/TensorSpan.cs | 90 +- .../Tensors/netcore/TensorSpanDebugView.cs | 5 - .../Tensors/netcore/TensorSpanExtensions.cs | 790 +++++- .../Tensors/netcore/TensorSpanHelpers.T.cs | 5 - .../Tensors/netcore/TensorSpanHelpers.cs | 109 +- .../src/System/ThrowHelper.cs | 14 +- .../tests/ReadOnlyTensorSpanTests.cs | 740 ++++++ .../tests/TensorSpanTests.cs | 735 +++++- .../tests/TensorTests.cs | 405 ++- 20 files changed, 4369 insertions(+), 1059 deletions(-) rename src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/{Common => }/IReadOnlyTensor.cs (88%) diff --git a/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx b/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx index a499e962b07bb..505dc853fcd16 100644 --- a/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx +++ b/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx @@ -219,4 +219,10 @@ Strides cannot be less than 0. + + Must be a 2d Tensor. + + + Incompatible dimensions for provided tensors. left.Lengths[1] == {0} while right.Lengths[1] == {1}. + \ No newline at end of file diff --git a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj index 485702c370cad..cfa810e067548 100644 --- a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj @@ -6,7 +6,7 @@ true Provides support for operating over tensors. ReferenceAssemblyExclusions.txt - true + false @@ -16,12 +16,12 @@ - + diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Common/IReadOnlyTensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/IReadOnlyTensor.cs similarity index 88% rename from src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Common/IReadOnlyTensor.cs rename to src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/IReadOnlyTensor.cs index 75c3b95e87209..e0bf1b94b6ec3 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Common/IReadOnlyTensor.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/IReadOnlyTensor.cs @@ -1,12 +1,8 @@ // 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 { @@ -20,8 +16,8 @@ public interface IReadOnlyTensor : IEnumerable nint FlattenedLength { get; } int Rank { get; } - T this[params ReadOnlySpan indexes] { get; } - T this[params ReadOnlySpan indexes] { get; } + T this[params scoped ReadOnlySpan indexes] { get; } + T this[params scoped ReadOnlySpan indexes] { get; } TSelf this[params scoped ReadOnlySpan ranges] { get; } ReadOnlyTensorSpan AsReadOnlyTensorSpan(); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ITensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ITensor.cs index 78fab614d1819..b88169543aa6f 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ITensor.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ITensor.cs @@ -1,12 +1,7 @@ // 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 { @@ -26,8 +21,8 @@ public interface ITensor bool IsReadOnly { get; } - new T this[params ReadOnlySpan indexes] { get; set; } - new T this[params ReadOnlySpan indexes] { get; set; } + new T this[params scoped ReadOnlySpan indexes] { get; set; } + new T this[params scoped ReadOnlySpan indexes] { get; set; } new TSelf this[params scoped ReadOnlySpan ranges] { get; set; } TensorSpan AsTensorSpan(); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs index 530bf27993e0f..57ec96024c27b 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs @@ -7,9 +7,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -using System.Runtime.Versioning; -using System.Text; +using static System.Runtime.InteropServices.JavaScript.JSType; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; @@ -43,7 +41,7 @@ public readonly ref struct ReadOnlyTensorSpan /// The target array. /// Returns default when is null. /// Thrown when is covariant and array's type is not exactly T[]. - public ReadOnlyTensorSpan(T[]? array) : this(array, 0, [], []) + public ReadOnlyTensorSpan(T[]? array) : this(array, 0, [array?.Length ?? 0], []) { } @@ -81,6 +79,9 @@ public ReadOnlyTensorSpan(T[]? array, Index startIndex, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty && array != null) + lengths = [array.Length]; + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); if (array == null) { @@ -92,18 +93,20 @@ public ReadOnlyTensorSpan(T[]? array, int start, scoped ReadOnlySpan lengt if (!typeof(T).IsValueType && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); + if (Environment.Is64BitProcess) { // See comment in Span.Slice for how this works. - if ((ulong)(uint)start + (ulong)(uint)maxElements > (ulong)(uint)array.Length) - ThrowHelper.ThrowArgumentOutOfRangeException(); + if ((ulong)(uint)start + (ulong)(uint)maxElements >= (ulong)(uint)array.Length && array.Length != 0) + ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); } else { - if ((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); + if (((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) && array.Length != 0) + ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); } _flattenedLength = linearLength; @@ -115,8 +118,8 @@ public ReadOnlyTensorSpan(T[]? array, int start, scoped ReadOnlySpan lengt } /// - /// Creates a new over the provided . The new will - /// have a rank of 1 and a length equal to the length of the provided . + /// Creates a new over the provided . The new will + /// have a rank of 1 and a length equal to the length of the provided . /// /// The target span. public ReadOnlyTensorSpan(ReadOnlySpan span) : this(span, [span.Length], []) { } @@ -130,18 +133,15 @@ public ReadOnlyTensorSpan(ReadOnlySpan span) : this(span, [span.Length], []) /// The strides for each dimension. Will be automatically calculated if not provided. public ReadOnlyTensorSpan(ReadOnlySpan span, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty) + lengths = [span.Length]; + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - if (span.IsEmpty) - { - if (linearLength != 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - this = default; - return; // returns default - } - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); - if (maxElements >= span.Length) + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); + if (maxElements >= span.Length && span.Length != 0) ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); _flattenedLength = linearLength; @@ -157,7 +157,7 @@ public ReadOnlyTensorSpan(ReadOnlySpan span, scoped ReadOnlySpan length /// have a rank of 1 and a length equal to the length of the provided . /// /// The target array. - public ReadOnlyTensorSpan(Array? array) : this(array, ReadOnlySpan.Empty, [], []) { } + public ReadOnlyTensorSpan(Array? array) : this(array, ReadOnlySpan.Empty, array == null ? [0] : (from dim in Enumerable.Range(0, array.Rank) select (nint)array.GetLength(dim)).ToArray(), []) { } /// /// Creates a new over the provided using the specified start offsets, lengths, and strides. @@ -169,9 +169,10 @@ public ReadOnlyTensorSpan(Array? array) : this(array, ReadOnlySpan.Empty, [ /// The strides for each dimension. Will be automatically calculated if not provided. public ReadOnlyTensorSpan(Array? array, scoped ReadOnlySpan start, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty && array != null) + lengths = (from dim in Enumerable.Range(0, array.Rank) select (nint)array.GetLength(dim)).ToArray(); + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint startOffset = TensorSpanHelpers.ComputeLinearIndex(start, strides, lengths); if (array == null) { if (!start.IsEmpty || linearLength != 0) @@ -182,16 +183,20 @@ public ReadOnlyTensorSpan(Array? array, scoped ReadOnlySpan start, scoped R if (!typeof(T).IsValueType && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + + nint startOffset = TensorSpanHelpers.ComputeStartOffsetSystemArray(array, start); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); if (Environment.Is64BitProcess) { // See comment in Span.Slice for how this works. - if ((ulong)(uint)startOffset + (ulong)(uint)maxElements > (ulong)(uint)array.Length) + if ((ulong)(uint)startOffset + (ulong)(uint)maxElements >= (ulong)(uint)array.Length && array.Length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); } else { - if ((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) + if (((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) && array.Length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); } @@ -213,9 +218,10 @@ public ReadOnlyTensorSpan(Array? array, scoped ReadOnlySpan start, scoped R /// The strides for each dimension. Will be automatically calculated if not provided. public ReadOnlyTensorSpan(Array? array, scoped ReadOnlySpan startIndex, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty && array != null) + lengths = (from dim in Enumerable.Range(0, array.Rank) select (nint)array.GetLength(dim)).ToArray(); + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint start = TensorSpanHelpers.ComputeLinearIndex(startIndex, strides, lengths); if (array == null) { if (!startIndex.IsEmpty || linearLength != 0) @@ -226,22 +232,26 @@ public ReadOnlyTensorSpan(Array? array, scoped ReadOnlySpan startIndex, if (!typeof(T).IsValueType && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + + nint startOffset = TensorSpanHelpers.ComputeStartOffsetSystemArray(array, startIndex); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); if (Environment.Is64BitProcess) { // See comment in Span.Slice for how this works. - if ((ulong)(uint)start + (ulong)(uint)maxElements > (ulong)(uint)array.Length) + if ((ulong)(uint)startOffset + (ulong)(uint)maxElements > (ulong)(uint)array.Length) ThrowHelper.ThrowArgumentOutOfRangeException(); } else { - if ((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) + if ((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) ThrowHelper.ThrowArgumentOutOfRangeException(); } _flattenedLength = linearLength; _memoryLength = array.Length; - _reference = ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), (nint)(uint)start /* force zero-extension */); + _reference = ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), (nint)(uint)startOffset /* force zero-extension */); _lengths = lengths.ToArray(); _strides = strides.ToArray(); @@ -276,13 +286,21 @@ public unsafe ReadOnlyTensorSpan(T* data, nint dataLength) : this(data, dataLeng [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe ReadOnlyTensorSpan(T* data, nint dataLength, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { - nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); + if (dataLength < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); - if (maxElements >= dataLength) + if (lengths.IsEmpty) + lengths = [dataLength]; + + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); + + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); + if (maxElements >= dataLength && dataLength != 0) ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); _flattenedLength = linearLength; diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.Factory.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.Factory.cs index e833c1b8ff607..0bd2f2986ceba 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.Factory.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.Factory.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.VisualBasic; #pragma warning disable CS8601 // Possible null reference assignment. #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. @@ -22,7 +23,7 @@ public static Tensor Create(scoped ReadOnlySpan lengths, bool pinned { nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); T[] values = pinned ? GC.AllocateArray((int)linearLength, pinned) : (new T[linearLength]); - return new Tensor(values, lengths, pinned); + return Create(values, lengths, [], pinned); } /// @@ -36,7 +37,7 @@ public static Tensor Create(scoped ReadOnlySpan lengths, scoped Read { nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); T[] values = pinned ? GC.AllocateArray((int)linearLength, pinned) : (new T[linearLength]); - return new Tensor(values, lengths, strides, pinned); + return Create(values, lengths, strides, pinned); } /// @@ -47,14 +48,7 @@ public static Tensor Create(scoped ReadOnlySpan lengths, scoped Read /// A indicating the lengths of each dimension. /// public static Tensor Create(T[] values, scoped ReadOnlySpan lengths) - where T : IEquatable - { - nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - if (linearLength != values.Length) - ThrowHelper.ThrowArgument_LengthsMustEqualArrayLength(); - - return new Tensor(values, lengths, false); - } + where T : IEquatable => Create(values, lengths, []); /// /// Creates a from the provided . If the product of the @@ -63,15 +57,12 @@ public static Tensor Create(T[] values, scoped ReadOnlySpan lengths) /// An array of the backing memory. /// A indicating the lengths of each dimension. /// A indicating the strides of each dimension. + /// A indicating whether the were pinned or not. /// - public static Tensor Create(T[] values, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) + public static Tensor Create(T[] values, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides, bool isPinned = false) where T : IEquatable { - nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - if (linearLength != values.Length) - ThrowHelper.ThrowArgument_LengthsMustEqualArrayLength(); - - return new Tensor(values, lengths, strides, false); + return new Tensor(values, lengths, strides, isPinned); } /// @@ -80,12 +71,8 @@ public static Tensor Create(T[] values, scoped ReadOnlySpan lengths, /// A indicating the lengths of each dimension. /// A whether the underlying data should be pinned or not. public static Tensor CreateUninitialized(scoped ReadOnlySpan lengths, bool pinned = false) - where T : IEquatable - { - nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - T[] values = GC.AllocateUninitializedArray((int)linearLength, pinned); - return new Tensor(values, lengths, pinned); - } + where T : IEquatable => CreateUninitialized(lengths, [], pinned); + /// /// Creates a and does not initialize it. If is true, the memory will be pinned. diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs index 380e3298f2aca..50007fcaedb45 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs @@ -5,9 +5,12 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; +using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using static System.Runtime.InteropServices.JavaScript.JSType; #pragma warning disable CS8601 // Possible null reference assignment. #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. @@ -32,7 +35,6 @@ public sealed class Tensor /// /// Creates a new empty Tensor. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Tensor() { _flattenedLength = 0; @@ -42,28 +44,43 @@ internal Tensor() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Tensor(T[] values, scoped ReadOnlySpan lengths, bool isPinned = false) - { - _flattenedLength = TensorSpanHelpers.CalculateTotalLength(lengths); - - _values = values; - _lengths = lengths.ToArray(); - _strides = TensorSpanHelpers.CalculateStrides(_lengths); - _isPinned = isPinned; - } + internal Tensor(T[]? values, ReadOnlySpan lengths, bool isPinned = false) : this(values, lengths, Array.Empty(), isPinned) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Tensor(T[] values, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides, bool isPinned = false) + internal Tensor(T[]? values, ReadOnlySpan lengths, ReadOnlySpan strides, bool isPinned = false) { - _flattenedLength = TensorSpanHelpers.CalculateTotalLength(lengths); + if (values == null) + { + if (_flattenedLength != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + _flattenedLength = 0; + _values = []; + _lengths = []; + _strides = []; + return; // returns default + } + + _lengths = lengths.IsEmpty ? [values.Length] : lengths.ToArray(); + + _flattenedLength = TensorSpanHelpers.CalculateTotalLength(_lengths); + _strides = strides.IsEmpty ? TensorSpanHelpers.CalculateStrides(_lengths, _flattenedLength) : strides.ToArray(); + TensorSpanHelpers.ValidateStrides(_strides, _lengths); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(_strides, _lengths); + + if (Environment.Is64BitProcess) + { + // See comment in Span.Slice for how this works. + if ((ulong)(uint)maxElements >= (ulong)(uint)values.Length && values.Length != 0) + ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); + } + else + { + if (((uint)maxElements > (uint)(values.Length)) && values.Length != 0) + ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); + } _values = values; - _lengths = lengths.ToArray(); - _strides = strides.ToArray(); - if (strides == Array.Empty()) - _strides = TensorSpanHelpers.CalculateStrides(lengths); _isPinned = isPinned; - } /// @@ -71,7 +88,7 @@ internal Tensor(T[] values, scoped ReadOnlySpan lengths, scoped ReadOnlySp /// /// A indicating the lengths of each dimension. /// A whether the underlying data should be pinned or not. - static Tensor ITensor, T>.Create(scoped ReadOnlySpan lengths, bool pinned) + static Tensor ITensor, T>.Create(ReadOnlySpan lengths, bool pinned) { nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); T[] values = pinned ? GC.AllocateArray((int)linearLength, pinned) : (new T[linearLength]); @@ -84,7 +101,7 @@ static Tensor ITensor, T>.Create(scoped ReadOnlySpan lengths, /// A indicating the lengths of each dimension. /// A indicating the strides of each dimension. /// A whether the underlying data should be pinned or not. - static Tensor ITensor, T>.Create(scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides, bool pinned) + static Tensor ITensor, T>.Create(ReadOnlySpan lengths, ReadOnlySpan strides, bool pinned) { nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); T[] values = pinned ? GC.AllocateArray((int)linearLength, pinned) : (new T[linearLength]); @@ -96,7 +113,7 @@ static Tensor ITensor, T>.Create(scoped ReadOnlySpan lengths, /// /// A indicating the lengths of each dimension. /// A whether the underlying data should be pinned or not. - static Tensor ITensor, T>.CreateUninitialized(scoped ReadOnlySpan lengths, bool pinned) + static Tensor ITensor, T>.CreateUninitialized(ReadOnlySpan lengths, bool pinned) { nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); T[] values = GC.AllocateUninitializedArray((int)linearLength, pinned); @@ -109,7 +126,7 @@ static Tensor ITensor, T>.CreateUninitialized(scoped ReadOnlySpanA indicating the lengths of each dimension. /// A indicating the strides of each dimension. /// A whether the underlying data should be pinned or not. - static Tensor ITensor, T>.CreateUninitialized(scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides, bool pinned) + static Tensor ITensor, T>.CreateUninitialized(ReadOnlySpan lengths, ReadOnlySpan strides, bool pinned) { nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); T[] values = GC.AllocateUninitializedArray((int)linearLength, pinned); @@ -347,6 +364,8 @@ public Tensor this[Tensor filter] } } + public static implicit operator Tensor(T[] array) => new Tensor(array, [array.Length]); + public static implicit operator TensorSpan(Tensor value) => new TensorSpan(ref MemoryMarshal.GetArrayDataReference(value._values), value._lengths, value._strides, value._flattenedLength); public static implicit operator ReadOnlyTensorSpan(Tensor value) => new ReadOnlyTensorSpan(ref MemoryMarshal.GetArrayDataReference(value._values), value._lengths, value._strides, value.FlattenedLength); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs index 4d1fdffceddcc..b5b7e5a89cede 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs @@ -6,11 +6,9 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Security.Cryptography; -using Microsoft.VisualBasic; using System.Text; using System.Buffers; -using System.Xml.Linq; +using static System.Runtime.InteropServices.JavaScript.JSType; #pragma warning disable CS8601 // Possible null reference assignment. #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. @@ -20,60 +18,6 @@ namespace System.Numerics.Tensors { public static partial class Tensor { - #region ToString - // REVIEW: WHAT SHOULD WE NAME THIS? WHERE DO WE WANT IT TO LIVE? - /// - /// Creates a representation of the ."/> - /// - /// The you want to represent as a string. - /// Maximum Length of each dimension - /// A representation of the - public static string ToString(this TensorSpan span, params scoped ReadOnlySpan maximumLengths) => ((ReadOnlyTensorSpan)span).ToString(maximumLengths); - - /// - /// Creates a representation of the ."/> - /// - /// - /// The you want to represent as a string. - /// Maximum Length of each dimension - public static string ToString(this ReadOnlyTensorSpan span, params scoped ReadOnlySpan maximumLengths) - { - var sb = new StringBuilder(); - scoped Span curIndexes; - nint[]? curIndexesArray; - if (span.Rank > 6) - { - curIndexesArray = ArrayPool.Shared.Rent(span.Rank); - curIndexes = curIndexesArray; - } - else - { - curIndexesArray = null; - curIndexes = stackalloc nint[span.Rank]; - } - - nint copiedValues = 0; - - T[] values = new T[span.Lengths[span.Rank - 1]]; - while (copiedValues < span._flattenedLength) - { - var sp = new ReadOnlyTensorSpan(ref Unsafe.Add(ref span._reference, TensorSpanHelpers.ComputeLinearIndex(curIndexes, span.Strides, span.Lengths)), [span.Lengths[span.Rank - 1]], [1], span.Lengths[span.Rank - 1]); - sb.Append('{'); - sp.FlattenTo(values); - sb.Append(string.Join(",", values)); - sb.AppendLine("}"); - - TensorSpanHelpers.AdjustIndexes(span.Rank - 2, 1, curIndexes, span._lengths); - copiedValues += span.Lengths[span.Rank - 1]; - } - - if (curIndexesArray != null) - ArrayPool.Shared.Return(curIndexesArray); - - return sb.ToString(); - } - #endregion - #region Resize /// /// Creates a new , allocates new memory, and copies the data from . If the final shape is smaller all data after @@ -120,6 +64,20 @@ public static TensorSpan Resize(TensorSpan input, scoped ReadOnlySpan + /// Broadcast the data from to the smallest broadcastable shape compatible with . Creates a new and allocates new memory. + /// + /// Input . + /// Other to make shapes broadcastable. + public static Tensor Broadcast(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators + { + nint[] newSize = TensorHelpers.GetSmallestBroadcastableSize(left.Lengths, right.Lengths); + + Tensor intermediate = BroadcastTo(left, newSize); + return Tensor.Create(intermediate.ToArray(), intermediate.Lengths); + } + /// /// Broadcast the data from to the new shape . Creates a new and allocates new memory. /// If the shape of the is not compatible with the new shape, an exception is thrown. @@ -178,49 +136,6 @@ internal static Tensor BroadcastTo(Tensor input, ReadOnlySpan sha return output; } - // Lazy/non-copy broadcasting, internal only for now. - /// - /// Broadcast the data from to the new shape . Creates a new - /// but no memory is allocated. It manipulates the strides to achieve this affect. - /// If the shape of the is not compatible with the new shape, an exception is thrown. - /// - /// Input . - /// of the desired new shape. - /// Thrown when the shapes are not broadcast compatible. - internal static TensorSpan BroadcastTo(TensorSpan input, scoped ReadOnlySpan shape) - where T : IEquatable, IEqualityOperators - { - if (input.Lengths.SequenceEqual(shape)) - return new TensorSpan(ref input._reference, shape, input.Strides, input._memoryLength); - - if (!TensorHelpers.AreShapesBroadcastCompatible(input.Lengths, shape)) - ThrowHelper.ThrowArgument_ShapesNotBroadcastCompatible(); - - nint newSize = TensorSpanHelpers.CalculateTotalLength(shape); - - if (newSize == input.FlattenedLength) - return Reshape(input, shape); - - nint[] intermediateShape = TensorHelpers.GetIntermediateShape(input.Lengths, shape.Length); - nint[] strides = new nint[shape.Length]; - - nint stride = 1; - - for (int i = strides.Length - 1; i >= 0; i--) - { - if ((intermediateShape[i] == 1 && shape[i] != 1) || (intermediateShape[i] == 1 && shape[i] == 1)) - strides[i] = 0; - else - { - strides[i] = stride; - stride *= intermediateShape[i]; - } - } - - TensorSpan output = new TensorSpan(ref input._reference, shape, strides, input._memoryLength); - - return output; - } #endregion #region Reverse @@ -294,79 +209,6 @@ public static Tensor Reverse(Tensor input, nint axis = -1) return output; } - - /// - /// Reverse the order of elements in the along the given axis. The shape of the tensor is preserved, but the elements are reordered. - /// defaults to -1 when not provided, which reverses the entire span. - /// - /// Input . - /// Axis along which to reverse over. The default, -1, will reverse over all of the axes of the left span. - public static TensorSpan Reverse(TensorSpan input, nint axis = -1) - where T : IEquatable, IEqualityOperators - { - if (axis == -1) - { - nint index = input.FlattenedLength - 1; - Span span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T temp; - for (int i = 0; i <= input.FlattenedLength / 2; i++) - { - temp = span[(int)index]; - span[(int)index] = span[i]; - span[i] = temp; - } - } - else - { - T[] values = new T[input.FlattenedLength]; - - nint copyLength = 1; - for (nint i = axis; i < input.Lengths.Length; i++) - { - copyLength *= input.Lengths[(int)i]; - } - copyLength /= input.Lengths[(int)axis]; - - scoped Span oIndices; - nint[]? oIndicesArray; - scoped Span iIndices; - nint[]? iIndicesArray; - if (input.Rank > 6) - { - oIndicesArray = ArrayPool.Shared.Rent(input.Rank); - oIndices = oIndicesArray; - iIndicesArray = ArrayPool.Shared.Rent(input.Rank); - iIndices = iIndicesArray; - } - else - { - oIndicesArray = null; - oIndices = stackalloc nint[input.Rank]; - iIndicesArray = null; - iIndices = stackalloc nint[input.Rank]; - } - - iIndices[(int)axis] = input.Lengths[(int)axis] - 1; - nint copiedValues = 0; - TensorSpan islice = input.Slice(input.Lengths); - while (copiedValues < input.FlattenedLength) - { - TensorSpanHelpers.Memmove(ref Unsafe.Add(ref values, TensorSpanHelpers.ComputeLinearIndex(oIndices, input.Strides, input.Lengths)), ref Unsafe.Add(ref islice._reference, TensorSpanHelpers.ComputeLinearIndex(iIndices, islice.Strides, islice.Lengths)), copyLength); - TensorSpanHelpers.AdjustIndexes((int)axis, 1, oIndices, input.Lengths); - TensorSpanHelpers.AdjustIndexesDown((int)axis, 1, iIndices, input.Lengths); - copiedValues += copyLength; - } - TensorSpanHelpers.Memmove(ref input._reference, ref values[0], input.FlattenedLength); - - if (oIndicesArray != null && iIndicesArray != null) - { - ArrayPool.Shared.Return(oIndicesArray); - ArrayPool.Shared.Return(iIndicesArray); - } - } - - return input; - } #endregion #region Split @@ -1030,41 +872,6 @@ public static Tensor Reshape(this Tensor input, params scoped ReadOnlyS nint[] strides = TensorSpanHelpers.CalculateStrides(arrLengths); return new Tensor(input._values, arrLengths, strides); } - - /// - /// Reshapes the tensor to the specified . If one of the lengths is -1, it will be calculated automatically. - /// Does not change the length of the underlying memory nor does it allocate new memory. If the new shape is not compatible with the old shape, - /// an exception is thrown. - /// - /// you want to reshape. - /// with the new dimensions. - public static TensorSpan Reshape(this TensorSpan input, params scoped ReadOnlySpan lengths) - where T : IEquatable, IEqualityOperators - { - nint[] arrLengths = lengths.ToArray(); - // Calculate wildcard info. - if (lengths.Contains(-1)) - { - if (lengths.Count(-1) > 1) - ThrowHelper.ThrowArgument_OnlyOneWildcard(); - nint tempTotal = input.FlattenedLength; - for (int i = 0; i < lengths.Length; i++) - { - if (lengths[i] != -1) - { - tempTotal /= lengths[i]; - } - } - arrLengths[lengths.IndexOf(-1)] = tempTotal; - - } - - nint tempLinear = TensorSpanHelpers.CalculateTotalLength(arrLengths); - if (tempLinear != input.FlattenedLength) - ThrowHelper.ThrowArgument_InvalidReshapeDimensions(); - nint[] strides = TensorSpanHelpers.CalculateStrides(arrLengths); - return new TensorSpan(ref input._reference, arrLengths, strides, input._memoryLength); - } #endregion #region Squeeze @@ -1410,700 +1217,1541 @@ public static Tensor Permute(Tensor input, params scoped ReadOnlySpan - /// Multiplies each element of with and returns a new with the result. + /// Takes the absolute value of each element of the and returns a new with the result. /// - /// Input - /// value to multiply by. - public static Tensor Multiply(Tensor input, T val) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor Abs(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = Create(input.Lengths, input.IsPinned); - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Multiply(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs); } /// - /// Multiplies each element of with in place. + /// Takes the absolute of each element of the in place. /// - /// Input - /// value to multiply by. - public static Tensor MultiplyInPlace(Tensor input, T val) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor AbsInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Multiply(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs, true); } + #endregion + #region Acos /// - /// Multiplies each element of with and returns a new with the result. - /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Takes the inverse cosine of each element of the and returns a new with the result. /// - /// Left for multiplication. - /// Right for multiplication. - public static Tensor Multiply(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor Acos(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acos); } /// - /// Multiplies each element of with in place. - /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Takes the inverse cosine of each element of the in place. /// - /// Left for multiplication. - /// Right for multiplication. - public static Tensor MultiplyInPlace(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor AcosInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acos, true); } + #endregion + #region Acosh /// - /// Multiplies each element of with and returns a new with the result. + /// Takes the inverse hyperbolic cosine of each element of the and returns a new with the result. /// - /// Input - /// value to multiply by. - public static TensorSpan Multiply(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor Acosh(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Multiply(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acosh); } /// - /// Multiplies each element of with in place. + /// Takes the inverse hyperbolic cosine of each element of the in place. /// - /// Input - /// value to multiply by. - public static TensorSpan MultiplyInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor AcoshInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Multiply(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acosh, true); } + #endregion + #region AcosPi /// - /// Multiplies each element of with and returns a new with the result. - /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Takes the inverse hyperbolic cosine divided by pi of each element of the and returns a new with the result. /// - /// Left for multiplication. - /// Right for multiplication. - public static TensorSpan Multiply(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor AcosPi(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AcosPi); } /// - /// Multiplies each element of with in place. - /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Takes the inverse hyperbolic cosine divided by pi of each element of the in place. /// - /// Left for multiplication. - /// Right for multiplication. - public static TensorSpan MultiplyInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static Tensor AcosPiInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AcosPi, true); } #endregion - #region Divide + #region Add /// - /// Divides each element of by and returns a new with the result. + /// Adds each element of to each element of and returns a new with the result. /// - /// Input . - /// The divisor - public static Tensor Divide(Tensor input, T val) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The of values to add. + /// The second of values to add. + public static Tensor Add(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = Create(input.Lengths, input.IsPinned); - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Divide(span, val, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Add); } /// - /// Divides each element of by in place. + /// Adds each element of to each element of in place. /// - /// Input . - /// The divisor. - public static Tensor DivideInPlace(Tensor input, T val) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The of values to add. + /// The second of values to add. + public static Tensor AddInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Divide(span, val, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Add, true); } /// - /// Divides by each element of and returns a new with the result."/> + /// Adds to each element of and returns a new with the result. /// - /// The value to be divided. - /// The divisor. - public static Tensor Divide(T val, Tensor input) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The of values to add. + /// The to add to each element of . + public static Tensor Add(Tensor input, T val) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); Tensor output = Create(input.Lengths, input.IsPinned); Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Divide(val, span, ospan); + TensorPrimitives.Add(span, val, ospan); return output; } /// - /// Divides by each element of in place. + /// Adds to each element of in place. /// - /// The value to be divided. - /// The divisor. - public static Tensor DivideInPlace(T val, Tensor input) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The of values to add. + /// The to add to each element of . + public static Tensor AddInPlace(Tensor input, T val) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); Tensor output = input; Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Divide(val, span, ospan); + TensorPrimitives.Add(span, val, ospan); return output; } + #endregion + #region Asin /// - /// Divides each element of by its corresponding element in and returns - /// a new with the result. + /// Takes the inverse sin of each element of the and returns a new with the result. /// - /// The to be divided. - /// The divisor. - public static Tensor Divide(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static Tensor Asin(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asin); } /// - /// Divides each element of by its corresponding element in in place. + /// Takes the inverse sine each element of the in place. /// - /// The to be divided. - /// The divisor. - public static Tensor DivideInPlace(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static Tensor AsinInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asin, true); } + #endregion + #region Asinh /// - /// Divides each element of by and returns a new with the result. + /// Takes the inverse hyperbolic sine of each element of the and returns a new with the result. /// - /// Input . - /// The divisor - public static TensorSpan Divide(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static Tensor Asinh(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asinh); } /// - /// Divides each element of by in place. + /// Takes the inverse hyperbolic sine each element of the in place. /// - /// Input . - /// The divisor - public static TensorSpan DivideInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static Tensor AsinhInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asinh, true); } + #endregion + #region AsinPi /// - /// Divides by each element of and returns a new with the result."/> + /// Takes the inverse hyperbolic sine divided by pi of each element of the and returns a new with the result. /// - /// The value to be divided. - /// The divisor. - public static TensorSpan Divide(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static Tensor AsinPi(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(val, span, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AsinPi); } /// - /// Divides by each element of in place. + /// Takes the inverse hyperbolic sine divided by pi of each element of the in place. /// - /// The value to be divided. - /// The divisor. - public static TensorSpan DivideInPlace(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static Tensor AsinPiInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(val, span, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AsinPi, true); } + #endregion + #region Atan /// - /// Divides each element of by its corresponding element in and returns - /// a new with the result. + /// Takes the arc tangent of each element of the and returns a new with the result. /// - /// The to be divided. - /// The divisor. - public static TensorSpan Divide(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The input + public static Tensor Atan(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atan); } /// - /// Divides each element of by its corresponding element in in place. + /// Takes the arc tangent of each element of the in place. /// - /// The to be divided. - /// The divisor. - public static TensorSpan DivideInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The input + public static Tensor AtanInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atan, true); } - #endregion - #region Subtract + #region Atan2 /// - /// Subtracts from each element of and returns a new with the result. + /// Takes the arc tangent of the two input and returns a new with the result. /// - /// The . - /// The to subtract. - public static Tensor Subtract(Tensor input, T val) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor Atan2(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = Create(input.Lengths, input.IsPinned); - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Subtract(span, val, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2); } /// - /// Subtracts from each element of in place. + /// Takes the arc tangent of the two input in place. /// - /// The . - /// The to subtract. - public static Tensor SubtractInPlace(Tensor input, T val) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor Atan2InPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Subtract(span, val, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2, true); } + #endregion + #region Atan2Pi /// - /// Subtracts each element of from and returns a new with the result. + /// Takes the arc tangent of the two input , divides each element by pi, and returns a new with the result. /// - /// The to be subtracted from. - /// The of values to subtract. - public static Tensor Subtract(T val, Tensor input) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor Atan2Pi(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = Create(input.Lengths, input.IsPinned); - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Subtract(val, span, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2Pi); } /// - /// Subtracts each element of from in place. + /// Takes the arc tangent of the two input , divides each element by pi in place. /// - /// The to be subtracted from. - /// The of values to subtract. - public static Tensor SubtractInPlace(T val, Tensor input) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor Atan2PiInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Subtract(val, span, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2Pi, true); } + #endregion + #region Atanh /// - /// Subtracts each element of from and returns a new with the result. + /// Takes the inverse hyperbolic tangent of each element of the and returns a new with the result. /// - /// The with values to be subtracted from. - /// The with values to subtract. - public static Tensor Subtract(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The input . + public static Tensor Atanh(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atanh); } /// - /// Subtracts each element of from in place. + /// Takes the inverse hyperbolic tangent of each element of the in place. /// - /// The with values to be subtracted from. - /// The with values to subtract. - public static Tensor SubtractInPlace(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The input . + public static Tensor AtanhInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atanh, true); } + #endregion + #region AtanPi /// - /// Subtracts from each element of and returns a new with the result. + /// Takes the inverse hyperbolic tangent divided by pi of each element of the and returns a new with the result. /// - /// The with values to be subtracted from. - /// The value to subtract. - public static TensorSpan Subtract(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The input. + public static Tensor AtanPi(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AtanPi); } /// - /// Subtracts from each element of in place. + /// Takes the inverse hyperbolic tangent divided by pi of each element of the in place. /// - /// The with values to be subtracted from. - /// The value to subtract. - public static TensorSpan SubtractInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The input. + public static Tensor AtanPiInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AtanPi, true); } + #endregion + #region BitwiseAnd /// - /// Subtracts each element of from and returns a new with the result. + /// Computes the element-wise bitwise and of the two input and returns a new with the result. /// - /// The value to be subtracted from. - /// The values to subtract. - public static TensorSpan Subtract(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor BitwiseAnd(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(val, span, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseAnd); } /// - /// Subtracts each element of from in place. + /// Computes the element-wise bitwise and of the two input in place. /// - /// The value to be subtracted from. - /// The values to subtract. - public static TensorSpan SubtractInPlace(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor BitwiseAndInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(val, span, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseAnd, true); } + #endregion + #region BitwiseOr /// - /// Subtracts each element of from and returns a new with the result. + /// Computes the element-wise bitwise of of the two input and returns a new with the result. /// - /// The of values to be subtracted from. - /// The of values to subtract. - public static TensorSpan Subtract(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor BitwiseOr(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseOr); } /// - /// Subtracts each element of from in place. + /// Computes the element-wise bitwise of of the two input in place. /// - /// The of values to be subtracted from. - /// The of values to subtract. - public static TensorSpan SubtractInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The left . + /// The right . + public static Tensor BitwiseOrInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract, true); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseOr, true); } - #endregion - #region Sum - + #region CubeRoot /// - /// Sums all the elements of the and returns the result. + /// Computes the element-wise cube root of the input and returns a new with the result. /// - /// The to sum. - public static T Sum(Tensor input) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The left . + public static Tensor CubeRoot(Tensor input) + where T : IEquatable, IEqualityOperators, IRootFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - return TensorPrimitives.Sum(span); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cbrt); } /// - /// Sums all the elements of the and returns the result. + /// Computes the element-wise cube root of the input in place. /// - /// The to sum. - public static T Sum(TensorSpan input) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The left . + public static Tensor CubeRootInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IRootFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - return TensorPrimitives.Sum(span); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cbrt, true); } - #endregion - #region Add + #region Ceiling /// - /// Adds each element of to each element of and returns a new with the result. + /// Computes the element-wise ceiling of the input and returns a new with the result. /// - /// The of values to add. - /// The second of values to add. - public static Tensor Add(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The left . + public static Tensor Ceiling(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Ceiling); } /// - /// Adds each element of to each element of in place. + /// Computes the element-wise ceiling of the input in place. /// - /// The of values to add. - /// The second of values to add. - public static Tensor AddInPlace(Tensor left, Tensor right) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The left . + public static Tensor CeilingInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Ceiling, true); } + #endregion + #region ConvertChecked /// - /// Adds to each element of and returns a new with the result. + /// Copies to a new converting each + /// value to a value. /// - /// The of values to add. - /// The to add to each element of . - public static Tensor Add(Tensor input, T val) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The input . + public static Tensor ConvertChecked(Tensor source) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = Create(input.Lengths, input.IsPinned); - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + return TensorPrimitivesHelperTFromSpanInTToSpanOut(source, TensorPrimitives.ConvertChecked); } + #endregion + #region ConvertSaturating /// - /// Adds to each element of in place. + /// Copies to a new converting each + /// value to a value. /// - /// The of values to add. - /// The to add to each element of . - public static Tensor AddInPlace(Tensor input, T val) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The input . + public static Tensor ConvertSaturating(Tensor source) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + return TensorPrimitivesHelperTFromSpanInTToSpanOut(source, TensorPrimitives.ConvertSaturating); } + #endregion + #region ConvertTruncating /// - /// Adds each element of to each element of and returns a new with the result. + /// Copies to a new converting each + /// value to a value. /// - /// The first of elements to add. - /// The second of elements to add. - public static TensorSpan Add(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The input . + public static Tensor ConvertTruncating(Tensor source) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add); + return TensorPrimitivesHelperTFromSpanInTToSpanOut(source, TensorPrimitives.ConvertTruncating); } + #endregion + #region CopySign /// - /// Adds each element of to each element of in place. + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors and returns a new tensor with the result. /// - /// The first of values to add. - /// The second of values to add. - public static TensorSpan AddInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// Input . + /// The number with the associated sign. + public static Tensor CopySign(Tensor input, T sign) + where T : IEquatable, IEqualityOperators, INumber { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add, true); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.CopySign(span, sign, ospan); + return output; } /// - /// Adds to each element of and returns a new with the result. + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors in place. /// - /// The of values to add. - /// The value to add to each element of . - public static TensorSpan Add(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// Input . + /// The number with the associated sign. + public static Tensor CopySignInPlace(Tensor input, T sign) + where T : IEquatable, IEqualityOperators, INumber { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + Span span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + TensorPrimitives.CopySign(span, sign, span); + return input; } /// - /// Adds to each element of in place. + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors and returns a new with the result. /// - /// The of values to add. - /// The value to add to each element of . - public static TensorSpan AddInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// Input . + /// The with the associated signs. + public static Tensor CopySign(Tensor input, Tensor sign) + where T : IEquatable, IEqualityOperators, INumber { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(input, sign, TensorPrimitives.CopySign); } - #endregion - - #region Norm /// - /// Takes the norm of the and returns the result. + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors in place. /// - /// The to take the norm of. - public static T Norm(Tensor input) - where T : IEquatable, IEqualityOperators, IRootFunctions + /// Input . + /// The with the associated signs. + public static Tensor CopySignInPlace(Tensor input, Tensor sign) + where T : IEquatable, IEqualityOperators, INumber { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - return TensorPrimitives.Norm(span); + return TensorPrimitivesHelperTwoSpanInSpanOut(input, sign, TensorPrimitives.CopySign, true); } + #endregion + #region Cos /// - /// Takes the norm of the and returns the result. + /// Takes the cosine of each element of the and returns a new with the result. /// - /// The to take the norm of. - public static T Norm(TensorSpan input) - where T : IEquatable, IEqualityOperators, IRootFunctions + /// The to take the cosine of. + public static Tensor Cos(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - return TensorPrimitives.Norm(span); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cos); } + /// + /// Takes the cosine of each element of the in place. + /// + /// The to take the cosine of. + public static Tensor CosInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cos, true); + } #endregion - #region Cos + #region Cosh /// - /// Takes the cosine of each element of the and returns a new with the result. + /// Takes the hyperbolic cosine of each element of the and returns a new with the result. /// /// The to take the cosine of. - public static Tensor Cos(Tensor input) - where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + public static Tensor Cosh(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cosh); + } + + /// + /// Takes the hyperbolic cosine of each element of the in place. + /// + /// The to take the cosine of. + public static Tensor CoshInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cosh, true); } + #endregion + #region CosineSimilarity /// - /// Takes the cosine of each element of the and returns a new with the result. + /// Compute cosine similarity between and . /// - /// The to take the cosine of. - public static TensorSpan Cos(TensorSpan input) + /// The first + /// The second + public static Tensor CosineSimilarity(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + if (left.Rank != 2) + ThrowHelper.ThrowArgument_2DTensorRequired(nameof(left)); + + if (right.Rank != 2) + ThrowHelper.ThrowArgument_2DTensorRequired(nameof(right)); + + if (left.Lengths[1] != right.Lengths[1]) + ThrowHelper.ThrowArgument_IncompatibleDimensions(left.Lengths[1], right.Lengths[1]); + + nint dim1 = left.Lengths[0]; + nint dim2 = right.Lengths[0]; + + T[] values = new T[dim1 * dim2]; + + scoped Span leftIndexes = stackalloc nint[2]; + scoped Span rightIndexes = stackalloc nint[2]; + + int outputOffset = 0; + + ReadOnlySpan lspan; + ReadOnlySpan rspan; + int rowLength = (int)left.Lengths[1]; + for (int i = 0; i < dim1; i++) + { + for (int j = 0; j < dim2; j++) + { + lspan = MemoryMarshal.CreateSpan(ref left[leftIndexes], rowLength); + rspan = MemoryMarshal.CreateSpan(ref right[rightIndexes], rowLength); + values[outputOffset++] = TensorPrimitives.CosineSimilarity(lspan, rspan); + rightIndexes[0]++; + } + rightIndexes[0] = 0; + leftIndexes[0]++; + } + + return Tensor.Create(values, [dim1, dim2]); + + } + #endregion + + #region CosPi + /// Computes the element-wise cosine of the value in the specified tensor that has been multiplied by Pi and returns a new with the results. + /// The input + /// + /// + /// This method effectively computes .CosPi([i]). + /// + /// + /// The angles in x must be in radians. Use or multiply by .Pi/180 to convert degrees to radians. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// + public static Tensor CosPi(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.CosPi); + } + + /// Computes the element-wise cosine of the value in the specified tensor that has been multiplied by Pi in place. + /// The input + /// + /// + /// This method effectively computes .CosPi([i]). + /// + /// + /// The angles in x must be in radians. Use or multiply by .Pi/180 to convert degrees to radians. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// + public static Tensor CosPiInPlace(Tensor input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.CosPi, true); } + #endregion + #region DegreesToRadians /// - /// Takes the cosine of each element of the in place. + /// Computes the element-wise conversion of each number of degrees in the specified tensor to radians and returns a new tensor with the results. /// - /// The to take the cosine of. - public static Tensor CosInPlace(Tensor input) + /// The input . + public static Tensor DegreesToRadians(Tensor input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.DegreesToRadians); } /// - /// Takes the cosine of each element of the in place. + /// Computes the element-wise conversion of each number of degrees in the specified tensor to radians in place. /// - /// The to take the cosine of. - public static TensorSpan CosInPlace(TensorSpan input) + /// The input . + public static Tensor DegreesToRadiansInPlace(Tensor input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.DegreesToRadians, true); + } + #endregion + + #region Distance + /// + /// Computes the distance between two points, specified as non-empty, equal-length tensors of numbers, in Euclidean space. + /// + /// The input . + /// The input . + public static T Distance(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperTwoSpanInTOut(left, right, TensorPrimitives.Distance); + } + + #endregion + + #region Divide + /// + /// Divides each element of by and returns a new with the result. + /// + /// Input . + /// The divisor + public static Tensor Divide(Tensor input, T val) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Divide(span, val, ospan); + return output; + } + + /// + /// Divides each element of by in place. + /// + /// Input . + /// The divisor. + public static Tensor DivideInPlace(Tensor input, T val) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Divide(span, val, ospan); + return output; + } + + /// + /// Divides by each element of and returns a new with the result."/> + /// + /// The value to be divided. + /// The divisor. + public static Tensor Divide(T val, Tensor input) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Divide(val, span, ospan); + return output; + } + + /// + /// Divides by each element of in place. + /// + /// The value to be divided. + /// The divisor. + public static Tensor DivideInPlace(T val, Tensor input) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Divide(val, span, ospan); + return output; + } + + /// + /// Divides each element of by its corresponding element in and returns + /// a new with the result. + /// + /// The to be divided. + /// The divisor. + public static Tensor Divide(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Divide); + } + + /// + /// Divides each element of by its corresponding element in in place. + /// + /// The to be divided. + /// The divisor. + public static Tensor DivideInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Divide, true); + } + #endregion + + #region Dot + /// + /// Computes the dot product of two tensors containing numbers. + /// + /// The input . + /// The input . + public static T Dot(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity, IMultiplicativeIdentity, IMultiplyOperators + { + return TensorPrimitivesHelperTwoSpanInTOut(left, right, TensorPrimitives.Dot); + } + + #endregion + + #region Exp + /// + /// Computes the element-wise result of raising e to the single-precision floating-point number powers in the specified tensor. + /// + /// The input . + public static Tensor Exp(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp); + } + + /// + /// Computes the element-wise result of raising e to the single-precision floating-point number powers in the specified tensor. + /// + /// The input . + public static Tensor ExpInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp, true); + } + #endregion + + #region Exp10 + /// + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor. + /// + /// The input . + public static Tensor Exp10(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10); + } + + /// + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor. + /// + /// The input . + public static Tensor Exp10InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10, true); + } + #endregion + + #region Exp10M1 + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor, minus one. + /// The input . + public static Tensor Exp10M1(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10M1); + } + + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor, minus one. + /// The input . + public static Tensor Exp10M1InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10M1, true); + } + #endregion + + #region Exp2 + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor. + /// The input . + public static Tensor Exp2(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2); + } + + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor. + /// The input . + public static Tensor Exp2InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2, true); + } + #endregion + + #region Exp2M1 + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor, minus one. + /// The input . + public static Tensor Exp2M1(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2M1); + } + + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor, minus one. + /// The input . + public static Tensor Exp2M1InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2M1, true); + } + #endregion + + #region ExpM1 + /// Computes the element-wise result of raising e to the number powers in the specified tensor, minus 1. + /// The input . + public static Tensor ExpM1(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.ExpM1); + } + + /// Computes the element-wise result of raising e to the number powers in the specified tensor, minus 1. + /// The input . + public static Tensor ExpM1InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.ExpM1, true); + } + #endregion + + #region Floor + /// Computes the element-wise floor of numbers in the specified tensor. + /// The input . + public static Tensor Floor(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Floor); + } + + /// Computes the element-wise floor of numbers in the specified tensor. + /// The input . + public static Tensor FloorInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Floor, true); + } + #endregion + + #region Hypotenuse + /// + /// Computes the element-wise hypotenuse given values from two tensors representing the lengths of the shorter sides in a right-angled triangle. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left . + /// Right . + public static Tensor Hypotenuse(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Hypot); + } + + /// + /// Computes the element-wise hypotenuse given values from two tensors representing the lengths of the shorter sides in a right-angled triangle. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left . + /// Right . + public static Tensor HypotenuseInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Hypot, true); + } + #endregion + + #region Ieee754Remainder + /// Computes the element-wise remainder of the numbers in the specified tensors. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Left . + /// Right . + public static Tensor Ieee754Remainder(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Ieee754Remainder); + } + + /// + /// Computes the element-wise remainder of the numbers in the specified tensors. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left . + /// Right . + public static Tensor Ieee754RemainderInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Ieee754Remainder, true); + } + #endregion + + #region ILogB + /// Computes the element-wise floor of numbers in the specified tensor. + /// The input . + public static Tensor ILogB(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperSpanInIntSpanOut(input, TensorPrimitives.ILogB); + } + #endregion + + #region IndexOfMax + /// Searches for the index of the largest number in the specified tensor. + /// The input . + public static int IndexOfMax(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + return TensorPrimitives.IndexOfMax(span); + } + #endregion + + #region IndexOfMaxMagnitude + /// Searches for the index of the number with the largest magnitude in the specified tensor. + /// The input . + public static int IndexOfMaxMagnitude(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + return TensorPrimitives.IndexOfMaxMagnitude(span); + } + #endregion + + #region IndexOfMin + /// Searches for the index of the smallest number in the specified tensor. + /// The input . + public static int IndexOfMin(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + return TensorPrimitives.IndexOfMin(span); + } + #endregion + + #region IndexOfMinMagnitude + /// + /// Searches for the index of the number with the smallest magnitude in the specified tensor. + /// + /// The input . + public static int IndexOfMinMagnitude(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + return TensorPrimitives.IndexOfMinMagnitude(span); + } + #endregion + + #region LeadingZeroCount + /// + /// Computes the element-wise leading zero count of numbers in the specified tensor. + /// + /// The input . + public static Tensor LeadingZeroCount(Tensor input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LeadingZeroCount); + } + + /// + /// Computes the element-wise leading zero count of numbers in the specified tensor. + /// + /// The input . + public static Tensor LeadingZeroCountInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LeadingZeroCount, true); + } + #endregion + + #region Log + /// + /// Takes the natural logarithm of each element of the and returns a new with the result. + /// + /// The to take the natural logarithm of. + public static Tensor Log(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log); + } + + /// + /// Takes the natural logarithm of each element of the in place. + /// + /// The to take the natural logarithm of. + public static Tensor LogInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log, true); + } + #endregion + + #region Log10 + /// + /// Takes the base 10 logarithm of each element of the and returns a new with the result. + /// + /// The to take the base 10 logarithm of. + public static Tensor Log10(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10); + } + + /// + /// Takes the base 10 logarithm of each element of the in place. + /// + /// The to take the base 10 logarithm of. + public static Tensor Log10InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10, true); + } + #endregion + + #region Log10P1 + /// + /// Takes the base 10 logarithm plus 1 of each element of the and returns a new with the result. + /// + /// The to take the base 10 logarithm of. + public static Tensor Log10P1(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10P1); + } + + /// + /// Takes the base 10 logarithm plus 1 of each element of the in place. + /// + /// The to take the base 10 logarithm of. + public static Tensor Log10P1InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10P1, true); + } + #endregion + + #region Log2 + /// + /// Takes the base 2 logarithm of each element of the and returns a new with the result. + /// + /// The to take the base 2 logarithm of. + public static Tensor Log2(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2); + } + + /// + /// Takes the base 2 logarithm of each element of the in place. + /// + /// The to take the base 2 logarithm of. + public static Tensor Log2InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2, true); + } + + #endregion + + #region Log2P1 + /// + /// Takes the base 2 logarithm plus 1 of each element of the and returns a new with the result. + /// + /// The to take the base 2 logarithm of. + public static Tensor Log2P1(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2P1); + } + + /// + /// Takes the base 2 logarithm plus 1 of each element of the in place. + /// + /// The to take the base 2 logarithm of. + public static Tensor Log2P1InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2P1, true); + } + #endregion + + #region LogP1 + /// + /// Takes the natural logarithm plus 1 of each element of the and returns a new with the result. + /// + /// The to take the natural logarithm of. + public static Tensor LogP1(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LogP1); + } + + /// + /// Takes the natural logarithm plus 1 of each element of the in place. + /// + /// The to take the natural logarithm of. + public static Tensor LogP1InPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LogP1, true); + } + #endregion + + #region Max + /// Searches for the largest number in the specified tensor. + /// The input .. + public static T Max(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.Max); + } + #endregion + + #region MaxMagnitude + /// Searches for the number with the largest magnitude in the specified tensor. + /// The input .. + public static T MaxMagnitude(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MaxMagnitude); + } + #endregion + + #region MaxNumber + /// Searches for the largest number in the specified tensor. + /// The input .. + public static T MaxNumber(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MaxNumber); + } + #endregion + + #region Min + /// Searches for the smallest number in the specified tensor. + /// The input . + public static T Min(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.Min); + } + #endregion + + #region MinMagnitude + /// Searches for the number with the smallest magnitude in the specified tensor. + /// The input . + public static T MinMagnitude(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MinMagnitude); + } + #endregion + + #region MinNumber + /// Searches for the smallest number in the specified tensor. + /// The input .. + public static T MinNumber(Tensor input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MinNumber); + } + #endregion + + #region Multiply + /// + /// Multiplies each element of with and returns a new with the result. + /// + /// Input + /// value to multiply by. + public static Tensor Multiply(Tensor input, T val) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Multiply(span, val, ospan); + return output; + } + + /// + /// Multiplies each element of with in place. + /// + /// Input + /// value to multiply by. + public static Tensor MultiplyInPlace(Tensor input, T val) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Multiply(span, val, ospan); + return output; + } + + /// + /// Multiplies each element of with and returns a new with the result. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left for multiplication. + /// Right for multiplication. + public static Tensor Multiply(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Multiply); + } + + /// + /// Multiplies each element of with in place. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left for multiplication. + /// Right for multiplication. + public static Tensor MultiplyInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Multiply, true); + } + #endregion + + #region Negate + /// Computes the element-wise negation of each number in the specified tensor. + /// The + public static Tensor Negate(Tensor input) + where T : IEquatable, IEqualityOperators, IUnaryNegationOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Negate); + } + + /// Computes the element-wise negation of each number in the specified tensor. + /// The + public static Tensor NegatePlace(Tensor input) + where T : IEquatable, IEqualityOperators, IUnaryNegationOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Negate, true); + } + #endregion + + #region Norm + /// + /// Takes the norm of the and returns the result. + /// + /// The to take the norm of. + public static T Norm(Tensor input) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.Norm); + } + #endregion + + #region OnesComplement + /// Computes the element-wise one's complement of numbers in the specified tensor. + /// The + public static Tensor OnesComplement(Tensor input) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.OnesComplement); + } + + /// Computes the element-wise one's complement of numbers in the specified tensor. + /// The + public static Tensor OnesComplementPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.OnesComplement, true); + } + #endregion + + #region PopCount + /// Computes the element-wise population count of numbers in the specified tensor. + /// The + public static Tensor PopCount(Tensor input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.PopCount); + } + + /// Computes the element-wise population count of numbers in the specified tensor. + /// The + public static Tensor PopCountPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.PopCount, true); + } + #endregion + + #region Pow + /// Computes the element-wise power of a number in a specified tensor raised to a number in another specified tensors. + /// The input . + /// The second input + public static Tensor Pow(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IPowerFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Pow); + } + + /// Computes the element-wise power of a number in a specified tensor raised to a number in another specified tensors. + /// The input . + /// The second input + public static Tensor PowInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IPowerFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Pow, true); + } + #endregion + + #region Product + /// Computes the product of all elements in the specified non-empty tensor of numbers. + /// The input . + public static T Product(Tensor input) + where T : IEquatable, IEqualityOperators, IMultiplicativeIdentity, IMultiplyOperators + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.Product); + } + #endregion + + #region RadiansToDegrees + /// Computes the element-wise conversion of each number of radians in the specified tensor to degrees. + /// The input . + public static Tensor RadiansToDegrees(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.RadiansToDegrees); + } + + /// Computes the element-wise conversion of each number of radians in the specified tensor to degrees. + /// The input . + public static Tensor RadiansToDegreesInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.RadiansToDegrees, true); + } + #endregion + + #region Reciprocal + /// Computes the element-wise reciprocal of numbers in the specified tensor. + /// The input . + public static Tensor Reciprocal(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Reciprocal); + } + + /// Computes the element-wise reciprocal of numbers in the specified tensor. + /// The input . + public static Tensor ReciprocalInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Reciprocal, true); + } + #endregion + + #region Round + /// Computes the element-wise rounding of the numbers in the specified tensor + /// The input . + public static Tensor Round(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Round); + } + + /// Computes the element-wise rounding of the numbers in the specified tensor + /// The input . + public static Tensor RoundInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Round, true); + } + #endregion + + #region Sigmoid + /// Computes the element-wise sigmoid function on the specified non-empty tensor of numbers. + /// The input . + public static Tensor Sigmoid(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sigmoid); + } + + /// Computes the element-wise sigmoid function on the specified non-empty tensor of numbers. + /// The input . + public static Tensor SigmoidInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sigmoid, true); + } + #endregion + + #region Sin + /// + /// Takes the sin of each element of the and returns a new with the result. + /// + /// The to take the sin of. + public static Tensor Sin(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sin); + } + + /// + /// Takes the sin of each element of the in place. + /// + /// The to take the sin of. + public static Tensor SinInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sin, true); + } + #endregion + + #region Sinh + /// Computes the element-wise hyperbolic sine of each radian angle in the specified tensor. + /// The to take the sin of. + public static Tensor Sinh(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sinh); } + /// Computes the element-wise hyperbolic sine of each radian angle in the specified tensor. + /// The to take the sin of. + public static Tensor SinhInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sinh, true); + } #endregion - #region Sin - /// - /// Takes the sin of each element of the and returns a new with the result. - /// + #region SinPi + /// Computes the element-wise sine of the value in the specified tensor that has been multiplied by Pi. /// The to take the sin of. - public static Tensor Sin(Tensor input) + public static Tensor SinPi(Tensor input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SinPi); } - /// - /// Takes the sin of each element of the and returns a new with the result. - /// - /// The to take the sin of. - public static TensorSpan Sin(TensorSpan input) + /// Computes the element-wise sine of the value in the specified tensor that has been multiplied by Pi. + /// The to take the sin of. + public static Tensor SinPiInPlace(Tensor input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SinPi, true); } + #endregion - /// - /// Takes the sin of each element of the in place. - /// + #region SoftMax + /// Computes the softmax function over the specified non-empty tensor of numbers. /// The to take the sin of. - public static Tensor SinInPlace(Tensor input) - where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + public static Tensor SoftMax(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SoftMax); } - /// - /// Takes the sin of each element of the in place. - /// - /// The to take the sin of. - public static TensorSpan SinInPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + /// Computes the softmax function over the specified non-empty tensor of numbers. + /// The to take the sin of. + public static Tensor SoftMaxInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SoftMax, true); } - #endregion #region Sqrt @@ -2114,177 +2762,260 @@ public static TensorSpan SinInPlace(TensorSpan input) public static Tensor Sqrt(Tensor input) where T : IEquatable, IEqualityOperators, IRootFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sqrt); } /// - /// Takes the square root of each element of the and returns a new with the result. + /// Takes the square root of each element of the in place. /// - /// The to take the square root of. - public static TensorSpan Sqrt(TensorSpan input) + /// The to take the square root of. + public static Tensor SqrtInPlace(Tensor input) where T : IEquatable, IEqualityOperators, IRootFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sqrt, true); } + #endregion + #region Subtract /// - /// Takes the square root of each element of the in place. + /// Subtracts from each element of and returns a new with the result. /// - /// The to take the square root of. - public static Tensor SqrtInPlace(Tensor input) - where T : IEquatable, IEqualityOperators, IRootFunctions + /// The . + /// The to subtract. + public static Tensor Subtract(Tensor input, T val) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt, true); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Subtract(span, val, ospan); + return output; } /// - /// Takes the square root of each element of the in place. + /// Subtracts from each element of in place. /// - /// The to take the square root of. - public static TensorSpan SqrtInPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, IRootFunctions + /// The . + /// The to subtract. + public static Tensor SubtractInPlace(Tensor input, T val) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt, true); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Subtract(span, val, ospan); + return output; } - #endregion - - #region Log /// - /// Takes the natural logarithm of each element of the and returns a new with the result. + /// Subtracts each element of from and returns a new with the result. /// - /// The to take the natural logarithm of. - public static Tensor Log(Tensor input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The to be subtracted from. + /// The of values to subtract. + public static Tensor Subtract(T val, Tensor input) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Subtract(val, span, ospan); + return output; } /// - /// Takes the natural logarithm of each element of the and returns a new with the result. + /// Subtracts each element of from in place. /// - /// The to take the natural logarithm of. - public static TensorSpan Log(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The to be subtracted from. + /// The of values to subtract. + public static Tensor SubtractInPlace(T val, Tensor input) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + TensorPrimitives.Subtract(val, span, ospan); + return output; } /// - /// Takes the natural logarithm of each element of the in place. + /// Subtracts each element of from and returns a new with the result. /// - /// The to take the natural logarithm of. - public static Tensor LogInPlace(Tensor input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The with values to be subtracted from. + /// The with values to subtract. + public static Tensor Subtract(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log, true); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Subtract); } /// - /// Takes the natural logarithm of each element of the in place. + /// Subtracts each element of from in place. /// - /// The to take the natural logarithm of. - public static TensorSpan LogInPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The with values to be subtracted from. + /// The with values to subtract. + public static Tensor SubtractInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log, true); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Subtract, true); } - #endregion - #region Log10 + #region Sum + /// - /// Takes the base 10 logarithm of each element of the and returns a new with the result. + /// Sums all the elements of the and returns the result. /// - /// The to take the base 10 logarithm of. - public static Tensor Log10(Tensor input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The to sum. + public static T Sum(Tensor input) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + return TensorPrimitives.Sum(span); } - /// - /// Takes the base 10 logarithm of each element of the and returns a new with the result. - /// - /// The to take the base 10 logarithm of. - public static TensorSpan Log10(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + #endregion + + #region Tan + /// Computes the element-wise tangent of the value in the specified tensor. + /// The to take the sin of. + public static Tensor Tan(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tan); } - /// - /// Takes the base 10 logarithm of each element of the in place. - /// - /// The to take the base 10 logarithm of. - public static Tensor Log10InPlace(Tensor input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// Computes the element-wise tangent of the value in the specified tensor. + /// The to take the sin of. + public static Tensor TanInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tan, true); } + #endregion - /// - /// Takes the base 10 logarithm of each element of the in place. - /// - /// The to take the base 10 logarithm of. - public static TensorSpan Log10InPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + #region Tanh + /// Computes the element-wise hyperbolic tangent of each radian angle in the specified tensor. + /// The to take the sin of. + public static Tensor Tanh(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tanh); + } + + /// Computes the element-wise hyperbolic tangent of each radian angle in the specified tensor. + /// The to take the sin of. + public static Tensor TanhInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tanh, true); } #endregion - #region Log2 - /// - /// Takes the base 2 logarithm of each element of the and returns a new with the result. - /// - /// The to take the base 2 logarithm of. - public static Tensor Log2(Tensor input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + #region TanPi + /// Computes the element-wise tangent of the value in the specified tensor that has been multiplied by Pi. + /// The to take the sin of. + public static Tensor TanPi(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TanPi); } - /// - /// Takes the base 2 logarithm of each element of the and returns a new with the result. - /// - /// The to take the base 2 logarithm of. - public static TensorSpan Log2(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// Computes the element-wise tangent of the value in the specified tensor that has been multiplied by Pi. + /// The to take the sin of. + public static Tensor TanPiInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TanPi, true); } + #endregion - /// - /// Takes the base 2 logarithm of each element of the in place. - /// - /// The to take the base 2 logarithm of. - public static Tensor Log2InPlace(Tensor input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + #region TrailingZeroCount + /// Computes the element-wise trailing zero count of numbers in the specified tensor. + /// The input . + public static Tensor TrailingZeroCount(Tensor input) + where T : IEquatable, IEqualityOperators, IBinaryInteger { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TrailingZeroCount); } - /// - /// Takes the base 2 logarithm of each element of the in place. - /// - /// The to take the base 2 logarithm of. - public static TensorSpan Log2InPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// Computes the element-wise trailing zero count of numbers in the specified tensor. + /// The input . + public static Tensor TrailingZeroCountInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TrailingZeroCount, true); + } + #endregion + + #region Truncate + /// Computes the element-wise truncation of numbers in the specified tensor. + /// The input . + public static Tensor Truncate(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Truncate); + } + + /// Computes the element-wise truncation of numbers in the specified tensor. + /// The input . + public static Tensor TruncateInPlace(Tensor input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Truncate, true); + } + #endregion + + #region Xor + /// Computes the element-wise XOR of numbers in the specified tensors. + /// The left . + /// The right . + public static Tensor Xor(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2, true); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Xor); } + /// Computes the element-wise XOR of numbers in the specified tensors. + /// The left . + /// The right . + public static Tensor XorInPlace(Tensor left, Tensor right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Xor, true); + } #endregion #region TensorPrimitivesHelpers - private delegate void PerformCalculationT1(ReadOnlySpan input, Span output) + private delegate void PerformCalculationTFromSpanInTToSpanOut(ReadOnlySpan input, Span output) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase; + + private delegate void PerformCalculationSpanInSpanOut(ReadOnlySpan input, Span output) + where T : IEquatable, IEqualityOperators; + + private delegate void PerformCalculationSpanInIntSpanOut(ReadOnlySpan input, Span output) where T : IEquatable, IEqualityOperators; - private delegate void PerformCalculationT1T2(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output) + private delegate T PerformCalculationTwoSpanInTOut(ReadOnlySpan input, ReadOnlySpan inputTwo) where T : IEquatable, IEqualityOperators; - private static Tensor TensorPrimitivesHelperT1(Tensor input, PerformCalculationT1 performCalculation, bool inPlace = false) + private delegate T PerformCalculationSpanInTOut(ReadOnlySpan input) + where T : IEquatable, IEqualityOperators; + + private delegate void PerformCalculationTwoSpanInSpanOut(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output) + where T : IEquatable, IEqualityOperators; + + private static Tensor TensorPrimitivesHelperSpanInIntSpanOut(Tensor input, PerformCalculationSpanInIntSpanOut performCalculation) + where T : IEquatable, IEqualityOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + performCalculation(span, ospan); + return output; + } + + private static Tensor TensorPrimitivesHelperSpanInSpanOut(Tensor input, PerformCalculationSpanInSpanOut performCalculation, bool inPlace = false) where T : IEquatable, IEqualityOperators { ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); @@ -2294,17 +3025,25 @@ private static Tensor TensorPrimitivesHelperT1(Tensor input, PerformCal return output; } - private static TensorSpan TensorPrimitivesHelperT1(TensorSpan input, PerformCalculationT1 performCalculation, bool inPlace = false) + private static T TensorPrimitivesHelperSpanInTOut(Tensor input, PerformCalculationSpanInTOut performCalculation) where T : IEquatable, IEqualityOperators { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = inPlace ? input : new TensorSpan(new T[input.FlattenedLength], 0, input.Lengths, input.Strides); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + return performCalculation(span); + } + + private static Tensor TensorPrimitivesHelperTFromSpanInTToSpanOut(Tensor input, PerformCalculationTFromSpanInTToSpanOut performCalculation) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); performCalculation(span, ospan); return output; } - private static Tensor TensorPrimitivesHelperT1T2(Tensor left, Tensor right, PerformCalculationT1T2 performCalculation, bool inPlace = false) + private static Tensor TensorPrimitivesHelperTwoSpanInSpanOut(Tensor left, Tensor right, PerformCalculationTwoSpanInSpanOut performCalculation, bool inPlace = false) where T : IEquatable, IEqualityOperators { if (inPlace && left.Lengths != right.Lengths) @@ -2410,37 +3149,15 @@ private static Tensor TensorPrimitivesHelperT1T2(Tensor left, Tensor return output; } - private static TensorSpan TensorPrimitivesHelperT1T2(TensorSpan left, TensorSpan right, PerformCalculationT1T2 performCalculation, bool inPlace = false) + private static T TensorPrimitivesHelperTwoSpanInTOut(Tensor left, Tensor right, PerformCalculationTwoSpanInTOut performCalculation) where T : IEquatable, IEqualityOperators { - if (inPlace && left.Lengths != right.Lengths) - ThrowHelper.ThrowArgument_InPlaceInvalidShape(); - - //ReadOnlySpan span = MemoryMarshal.CreateSpan(ref tensor._reference, (int)tensor.FlattenedLength); - //ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); - //TensorSpan output = inPlace ? tensor : Create(tensor.IsPinned, tensor.Lengths); - //Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - //performCalculation(span, rspan, ospan); - //return output; - - TensorSpan output; - if (inPlace) - { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref left._reference, (int)left.FlattenedLength); - ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); - output = left; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - performCalculation(span, rspan, ospan); - } // If not in place but sizes are the same. - else if (left.Lengths.SequenceEqual(right.Lengths)) + if (left.Lengths.SequenceEqual(right.Lengths)) { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref left._reference, (int)left.FlattenedLength); - ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); - output = new TensorSpan(new T[left.FlattenedLength], 0, left.Lengths, left.Strides); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - performCalculation(span, rspan, ospan); - return output; + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref left.AsTensorSpan()._reference, (int)left.FlattenedLength); + ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right.AsTensorSpan()._reference, (int)right.FlattenedLength); + return performCalculation(span, rspan); } // Not in place and broadcasting needs to happen. else @@ -2448,78 +3165,15 @@ private static TensorSpan TensorPrimitivesHelperT1T2(TensorSpan left, T // Have a couple different possible cases here. // 1 - Both tensors have row contiguous memory (i.e. a 1x5 being broadcast to a 5x5) // 2 - One tensor has row contiguous memory and the right has column contiguous memory (i.e. a 1x5 and a 5x1) + // Because we are returning a single T though we need to actual realize the broadcasts at this point to perform the calculations. - nint[] newSize = TensorHelpers.GetSmallestBroadcastableSize(left.Lengths, right.Lengths); - - TensorSpan broadcastedLeft = Tensor.BroadcastTo(left, newSize); - TensorSpan broadcastedRight = Tensor.BroadcastTo(right, newSize); - - output = new TensorSpan(new T[TensorSpanHelpers.CalculateTotalLength(newSize)], newSize, default); - nint rowLength = newSize[^1]; - Span ospan; - Span ispan; - Span buffer = new T[rowLength]; - - scoped Span curIndex; - nint[]? curIndexArray; - if (newSize.Length > 6) - { - curIndexArray = ArrayPool.Shared.Rent(newSize.Length); - curIndex = curIndexArray; - } - else - { - curIndexArray = null; - curIndex = stackalloc nint[newSize.Length]; - } - - int outputOffset = 0; - // ADD IN CASE WHERE NEITHER ARE ROW CONTIGUOUS - // tensor not row contiguous - if (broadcastedLeft.Strides[^1] == 0) - { - while (outputOffset < output.FlattenedLength) - { - ospan = MemoryMarshal.CreateSpan(ref Unsafe.Add(ref output._reference, outputOffset), (int)rowLength); - buffer.Fill(broadcastedLeft[curIndex]); - ispan = MemoryMarshal.CreateSpan(ref broadcastedRight[curIndex], (int)rowLength); - performCalculation(buffer, ispan, ospan); - outputOffset += (int)rowLength; - TensorSpanHelpers.AdjustIndexes(broadcastedLeft.Rank - 2, 1, curIndex, broadcastedLeft.Lengths); - } - } - // right not row contiguous - else if (broadcastedRight.Strides[^1] == 0) - { - while (outputOffset < output.FlattenedLength) - { - ospan = MemoryMarshal.CreateSpan(ref Unsafe.Add(ref output._reference, outputOffset), (int)rowLength); - buffer.Fill(broadcastedRight[curIndex]); - ispan = MemoryMarshal.CreateSpan(ref broadcastedLeft[curIndex], (int)rowLength); - performCalculation(ispan, buffer, ospan); - outputOffset += (int)rowLength; - TensorSpanHelpers.AdjustIndexes(broadcastedLeft.Rank - 2, 1, curIndex, broadcastedLeft.Lengths); - } - } - // both row contiguous - else - { - Span rspan; - while (outputOffset < output.FlattenedLength) - { - ospan = MemoryMarshal.CreateSpan(ref Unsafe.Add(ref output._reference, outputOffset), (int)rowLength); - ispan = MemoryMarshal.CreateSpan(ref broadcastedLeft[curIndex], (int)rowLength); - rspan = MemoryMarshal.CreateSpan(ref broadcastedRight[curIndex], (int)rowLength); - performCalculation(ispan, rspan, ospan); - outputOffset += (int)rowLength; - TensorSpanHelpers.AdjustIndexes(broadcastedLeft.Rank - 2, 1, curIndex, broadcastedLeft.Lengths); - } - } + var broadcastedLeft = Tensor.Broadcast(left, right); + var broadcastedRight = Tensor.Broadcast(right, left); - if (curIndexArray != null) - ArrayPool.Shared.Return(curIndexArray); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref broadcastedLeft.AsTensorSpan()._reference, (int)broadcastedLeft.FlattenedLength); + ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref broadcastedRight.AsTensorSpan()._reference, (int)broadcastedRight.FlattenedLength); + return performCalculation(span, rspan); } - return output; } #endregion #endregion diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorHelpers.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorHelpers.cs index 585bc4e344140..0fd46eb8d58f5 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorHelpers.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorHelpers.cs @@ -2,20 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Linq; -using System.Net.NetworkInformation; -using System.Reflection.Metadata.Ecma335; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using Microsoft.CSharp.RuntimeBinder; -using Microsoft.VisualBasic; namespace System.Numerics.Tensors { diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs index 68d7781f21cd0..27d11cf14ce72 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs @@ -7,7 +7,7 @@ namespace System.Numerics.Tensors { public static partial class TensorPrimitives { - /// Computes the element-wise conversion of each number of degrees in the specified tensor to radiansx. + /// Computes the element-wise conversion of each number of degrees in the specified tensor to radians. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs index 30b9bc5178519..f0c46347ac244 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs @@ -7,7 +7,7 @@ namespace System.Numerics.Tensors { public static partial class TensorPrimitives { - /// Computes the element-wise hypotensue given values from two tensors representing the lengths of the shorter sides in a right-angled triangle. + /// Computes the element-wise hypotenuse given values from two tensors representing the lengths of the shorter sides in a right-angled triangle. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs index 77c795fb8c119..c92c243bf3a88 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs @@ -7,9 +7,6 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; -using System.Runtime.Versioning; -using System.Text; using static System.Runtime.InteropServices.JavaScript.JSType; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; @@ -46,7 +43,7 @@ public readonly ref struct TensorSpan /// Returns default when is null. /// Thrown when is covariant and array's type is not exactly T[]. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TensorSpan(T[]? array) : this(array, 0, [], []) + public TensorSpan(T[]? array) : this(array, 0, [array?.Length ?? 0], []) { } @@ -84,6 +81,9 @@ public TensorSpan(T[]? array, Index startIndex, scoped ReadOnlySpan length [MethodImpl(MethodImplOptions.AggressiveInlining)] public TensorSpan(T[]? array, int start, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty && array != null) + lengths = [array.Length]; + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); if (array == null) { @@ -95,19 +95,20 @@ public TensorSpan(T[]? array, int start, scoped ReadOnlySpan lengths, scop if (!typeof(T).IsValueType && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); if (Environment.Is64BitProcess) { // See comment in Span.Slice for how this works. - if ((ulong)(uint)start + (ulong)(uint)maxElements > (ulong)(uint)array.Length) - ThrowHelper.ThrowArgumentOutOfRangeException(); + if ((ulong)(uint)start + (ulong)(uint)maxElements >= (ulong)(uint)array.Length && array.Length != 0) + ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); } else { - if ((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); + if (((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) && array.Length != 0) + ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); } _flattenedLength = linearLength; @@ -134,18 +135,16 @@ public TensorSpan(Span span) : this(span, [span.Length], []) { } /// The strides for each dimension. Will be automatically calculated if not provided. public TensorSpan(Span span, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty) + lengths = [span.Length]; + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - if (span.IsEmpty) - { - if (linearLength != 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - this = default; - return; // returns default - } - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); - if (maxElements > span.Length) + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); + if (maxElements >= span.Length && span.Length != 0) ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); _flattenedLength = linearLength; @@ -161,7 +160,7 @@ public TensorSpan(Span span, scoped ReadOnlySpan lengths, scoped ReadOn /// have a rank of 1 and a length equal to the length of the provided . /// /// The target array. - public TensorSpan(Array? array) : this(array, ReadOnlySpan.Empty, [], []) { } + public TensorSpan(Array? array) : this(array, ReadOnlySpan.Empty, array == null ? [0] : (from dim in Enumerable.Range(0, array.Rank) select (nint)array.GetLength(dim)).ToArray(), []) { } /// /// Creates a new over the provided using the specified start offsets, lengths, and strides. @@ -173,9 +172,11 @@ public TensorSpan(Array? array) : this(array, ReadOnlySpan.Empty, [], []) { /// The strides for each dimension. Will be automatically calculated if not provided. public TensorSpan(Array? array, scoped ReadOnlySpan start, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty && array != null) + lengths = (from dim in Enumerable.Range(0, array.Rank) select (nint)array.GetLength(dim)).ToArray(); + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint startOffset = TensorSpanHelpers.ComputeLinearIndex(start, strides, lengths); + if (array == null) { if (!start.IsEmpty || linearLength != 0) @@ -186,16 +187,20 @@ public TensorSpan(Array? array, scoped ReadOnlySpan start, scoped ReadOnlyS if (!typeof(T).IsValueType && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + + nint startOffset = TensorSpanHelpers.ComputeStartOffsetSystemArray(array, start); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); if (Environment.Is64BitProcess) { // See comment in Span.Slice for how this works. - if ((ulong)(uint)startOffset + (ulong)(uint)maxElements > (ulong)(uint)array.Length) + if ((ulong)(uint)startOffset + (ulong)(uint)maxElements >= (ulong)(uint)array.Length && array.Length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); } else { - if ((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) + if (((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) && array.Length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); } @@ -217,9 +222,12 @@ public TensorSpan(Array? array, scoped ReadOnlySpan start, scoped ReadOnlyS /// The strides for each dimension. Will be automatically calculated if not provided. public TensorSpan(Array? array, scoped ReadOnlySpan startIndex, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { + if (lengths.IsEmpty && array != null) + lengths = (from dim in Enumerable.Range(0, array.Rank) select (nint)array.GetLength(dim)).ToArray(); + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint start = TensorSpanHelpers.ComputeLinearIndex(startIndex, strides, lengths); + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); if (array == null) { if (!startIndex.IsEmpty || linearLength != 0) @@ -230,22 +238,23 @@ public TensorSpan(Array? array, scoped ReadOnlySpan startIndex, scoped R if (!typeof(T).IsValueType && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); + nint startOffset = TensorSpanHelpers.ComputeStartOffsetSystemArray(array, startIndex); + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); if (Environment.Is64BitProcess) { // See comment in Span.Slice for how this works. - if ((ulong)(uint)start + (ulong)(uint)maxElements > (ulong)(uint)array.Length) + if ((ulong)(uint)startOffset + (ulong)(uint)maxElements > (ulong)(uint)array.Length) ThrowHelper.ThrowArgumentOutOfRangeException(); } else { - if ((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) + if ((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) ThrowHelper.ThrowArgumentOutOfRangeException(); } _flattenedLength = linearLength; _memoryLength = array.Length; - _reference = ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), (nint)(uint)start /* force zero-extension */); + _reference = ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), (nint)(uint)startOffset /* force zero-extension */); _lengths = lengths.ToArray(); _strides = strides.ToArray(); @@ -280,13 +289,22 @@ public unsafe TensorSpan(T* data, nint dataLength) : this(data, dataLength, [dat [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe TensorSpan(T* data, nint dataLength, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides) { - nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); + if (dataLength < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths) : strides; - nint maxElements = TensorSpanHelpers.ComputeMaxElementCount(strides, lengths); - if (maxElements > dataLength) + if (lengths.IsEmpty) + lengths = [dataLength]; + + nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths); + + strides = strides.IsEmpty ? (ReadOnlySpan)TensorSpanHelpers.CalculateStrides(lengths, linearLength) : strides; + TensorSpanHelpers.ValidateStrides(strides, lengths); + + nint maxElements = TensorSpanHelpers.ComputeMaxLinearIndex(strides, lengths); + if (maxElements >= dataLength && dataLength != 0) ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); _flattenedLength = linearLength; _memoryLength = dataLength; diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanDebugView.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanDebugView.cs index 151f04fd67dd9..ab6073a52341a 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanDebugView.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanDebugView.cs @@ -1,12 +1,7 @@ // 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.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace System.Numerics.Tensors { diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs index 629ffb27f64da..aa975e04907b7 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs @@ -1,13 +1,10 @@ // 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.Collections.Generic; -using System.Linq; +using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using System.Threading.Tasks; namespace System.Numerics.Tensors { @@ -29,5 +26,790 @@ public static class TensorSpan /// The shape for the /// public static TensorSpan AsTensorSpan(this T[]? array, params scoped ReadOnlySpan shape) => new(array, 0, shape, default); + + #region ToString + // REVIEW: WHAT SHOULD WE NAME THIS? WHERE DO WE WANT IT TO LIVE? + /// + /// Creates a representation of the ."/> + /// + /// The you want to represent as a string. + /// Maximum Length of each dimension + /// A representation of the + public static string ToString(this TensorSpan span, params scoped ReadOnlySpan maximumLengths) => ((ReadOnlyTensorSpan)span).ToString(maximumLengths); + + /// + /// Creates a representation of the ."/> + /// + /// + /// The you want to represent as a string. + /// Maximum Length of each dimension + public static string ToString(this ReadOnlyTensorSpan span, params scoped ReadOnlySpan maximumLengths) + { + var sb = new StringBuilder(); + scoped Span curIndexes; + nint[]? curIndexesArray; + if (span.Rank > 6) + { + curIndexesArray = ArrayPool.Shared.Rent(span.Rank); + curIndexes = curIndexesArray; + } + else + { + curIndexesArray = null; + curIndexes = stackalloc nint[span.Rank]; + } + + nint copiedValues = 0; + + T[] values = new T[span.Lengths[span.Rank - 1]]; + while (copiedValues < span._flattenedLength) + { + var sp = new ReadOnlyTensorSpan(ref Unsafe.Add(ref span._reference, TensorSpanHelpers.ComputeLinearIndex(curIndexes, span.Strides, span.Lengths)), [span.Lengths[span.Rank - 1]], [1], span.Lengths[span.Rank - 1]); + sb.Append('{'); + sp.FlattenTo(values); + sb.Append(string.Join(",", values)); + sb.AppendLine("}"); + + TensorSpanHelpers.AdjustIndexes(span.Rank - 2, 1, curIndexes, span._lengths); + copiedValues += span.Lengths[span.Rank - 1]; + } + + if (curIndexesArray != null) + ArrayPool.Shared.Return(curIndexesArray); + + return sb.ToString(); + } + #endregion + + // Lazy/non-copy broadcasting, internal only for now. + /// + /// Broadcast the data from to the new shape . Creates a new + /// but no memory is allocated. It manipulates the strides to achieve this affect. + /// If the shape of the is not compatible with the new shape, an exception is thrown. + /// + /// Input . + /// of the desired new shape. + /// Thrown when the shapes are not broadcast compatible. + internal static TensorSpan BroadcastTo(TensorSpan input, scoped ReadOnlySpan shape) + where T : IEquatable, IEqualityOperators + { + if (input.Lengths.SequenceEqual(shape)) + return new TensorSpan(ref input._reference, shape, input.Strides, input._memoryLength); + + if (!TensorHelpers.AreShapesBroadcastCompatible(input.Lengths, shape)) + ThrowHelper.ThrowArgument_ShapesNotBroadcastCompatible(); + + nint newSize = TensorSpanHelpers.CalculateTotalLength(shape); + + if (newSize == input.FlattenedLength) + return Reshape(input, shape); + + nint[] intermediateShape = TensorHelpers.GetIntermediateShape(input.Lengths, shape.Length); + nint[] strides = new nint[shape.Length]; + + nint stride = 1; + + for (int i = strides.Length - 1; i >= 0; i--) + { + if ((intermediateShape[i] == 1 && shape[i] != 1) || (intermediateShape[i] == 1 && shape[i] == 1)) + strides[i] = 0; + else + { + strides[i] = stride; + stride *= intermediateShape[i]; + } + } + + TensorSpan output = new TensorSpan(ref input._reference, shape, strides, input._memoryLength); + + return output; + } + + /// + /// Reverse the order of elements in the along the given axis. The shape of the tensor is preserved, but the elements are reordered. + /// defaults to -1 when not provided, which reverses the entire span. + /// + /// Input . + /// Axis along which to reverse over. The default, -1, will reverse over all of the axes of the left span. + public static TensorSpan Reverse(TensorSpan input, nint axis = -1) + where T : IEquatable, IEqualityOperators + { + if (axis == -1) + { + nint index = input.FlattenedLength - 1; + Span span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T temp; + for (int i = 0; i <= input.FlattenedLength / 2; i++) + { + temp = span[(int)index]; + span[(int)index] = span[i]; + span[i] = temp; + } + } + else + { + T[] values = new T[input.FlattenedLength]; + + nint copyLength = 1; + for (nint i = axis; i < input.Lengths.Length; i++) + { + copyLength *= input.Lengths[(int)i]; + } + copyLength /= input.Lengths[(int)axis]; + + scoped Span oIndices; + nint[]? oIndicesArray; + scoped Span iIndices; + nint[]? iIndicesArray; + if (input.Rank > 6) + { + oIndicesArray = ArrayPool.Shared.Rent(input.Rank); + oIndices = oIndicesArray; + iIndicesArray = ArrayPool.Shared.Rent(input.Rank); + iIndices = iIndicesArray; + } + else + { + oIndicesArray = null; + oIndices = stackalloc nint[input.Rank]; + iIndicesArray = null; + iIndices = stackalloc nint[input.Rank]; + } + + iIndices[(int)axis] = input.Lengths[(int)axis] - 1; + nint copiedValues = 0; + TensorSpan islice = input.Slice(input.Lengths); + while (copiedValues < input.FlattenedLength) + { + TensorSpanHelpers.Memmove(ref Unsafe.Add(ref values, TensorSpanHelpers.ComputeLinearIndex(oIndices, input.Strides, input.Lengths)), ref Unsafe.Add(ref islice._reference, TensorSpanHelpers.ComputeLinearIndex(iIndices, islice.Strides, islice.Lengths)), copyLength); + TensorSpanHelpers.AdjustIndexes((int)axis, 1, oIndices, input.Lengths); + TensorSpanHelpers.AdjustIndexesDown((int)axis, 1, iIndices, input.Lengths); + copiedValues += copyLength; + } + TensorSpanHelpers.Memmove(ref input._reference, ref values[0], input.FlattenedLength); + + if (oIndicesArray != null && iIndicesArray != null) + { + ArrayPool.Shared.Return(oIndicesArray); + ArrayPool.Shared.Return(iIndicesArray); + } + } + + return input; + } + + /// + /// Reshapes the tensor to the specified . If one of the lengths is -1, it will be calculated automatically. + /// Does not change the length of the underlying memory nor does it allocate new memory. If the new shape is not compatible with the old shape, + /// an exception is thrown. + /// + /// you want to reshape. + /// with the new dimensions. + public static TensorSpan Reshape(this TensorSpan input, params scoped ReadOnlySpan lengths) + where T : IEquatable, IEqualityOperators + { + nint[] arrLengths = lengths.ToArray(); + // Calculate wildcard info. + if (lengths.Contains(-1)) + { + if (lengths.Count(-1) > 1) + ThrowHelper.ThrowArgument_OnlyOneWildcard(); + nint tempTotal = input.FlattenedLength; + for (int i = 0; i < lengths.Length; i++) + { + if (lengths[i] != -1) + { + tempTotal /= lengths[i]; + } + } + arrLengths[lengths.IndexOf(-1)] = tempTotal; + + } + + nint tempLinear = TensorSpanHelpers.CalculateTotalLength(arrLengths); + if (tempLinear != input.FlattenedLength) + ThrowHelper.ThrowArgument_InvalidReshapeDimensions(); + nint[] strides = TensorSpanHelpers.CalculateStrides(arrLengths); + return new TensorSpan(ref input._reference, arrLengths, strides, input._memoryLength); + } + + #region TensorPrimitives + #region Multiply + /// + /// Multiplies each element of with and returns a new with the result. + /// + /// Input + /// value to multiply by. + public static TensorSpan Multiply(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Multiply(span, val, ospan); + return output; + } + + /// + /// Multiplies each element of with in place. + /// + /// Input + /// value to multiply by. + public static TensorSpan MultiplyInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Multiply(span, val, ospan); + return output; + } + + /// + /// Multiplies each element of with and returns a new with the result. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left for multiplication. + /// Right for multiplication. + public static TensorSpan Multiply(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply); + } + + /// + /// Multiplies each element of with in place. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left for multiplication. + /// Right for multiplication. + public static TensorSpan MultiplyInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply, true); + } + #endregion + + #region Divide + /// + /// Divides each element of by and returns a new with the result. + /// + /// Input . + /// The divisor + public static TensorSpan Divide(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(span, val, ospan); + return output; + } + + /// + /// Divides each element of by in place. + /// + /// Input . + /// The divisor + public static TensorSpan DivideInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(span, val, ospan); + return output; + } + + /// + /// Divides by each element of and returns a new with the result."/> + /// + /// The value to be divided. + /// The divisor. + public static TensorSpan Divide(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(val, span, ospan); + return output; + } + + /// + /// Divides by each element of in place. + /// + /// The value to be divided. + /// The divisor. + public static TensorSpan DivideInPlace(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(val, span, ospan); + return output; + } + + /// + /// Divides each element of by its corresponding element in and returns + /// a new with the result. + /// + /// The to be divided. + /// The divisor. + public static TensorSpan Divide(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide); + } + + /// + /// Divides each element of by its corresponding element in in place. + /// + /// The to be divided. + /// The divisor. + public static TensorSpan DivideInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide, true); + } + #endregion + + #region Subtract + /// + /// Subtracts from each element of and returns a new with the result. + /// + /// The with values to be subtracted from. + /// The value to subtract. + public static TensorSpan Subtract(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, ISubtractionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(span, val, ospan); + return output; + } + + /// + /// Subtracts from each element of in place. + /// + /// The with values to be subtracted from. + /// The value to subtract. + public static TensorSpan SubtractInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, ISubtractionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(span, val, ospan); + return output; + } + + /// + /// Subtracts each element of from and returns a new with the result. + /// + /// The value to be subtracted from. + /// The values to subtract. + public static TensorSpan Subtract(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, ISubtractionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(val, span, ospan); + return output; + } + + /// + /// Subtracts each element of from in place. + /// + /// The value to be subtracted from. + /// The values to subtract. + public static TensorSpan SubtractInPlace(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, ISubtractionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(val, span, ospan); + return output; + } + + /// + /// Subtracts each element of from and returns a new with the result. + /// + /// The of values to be subtracted from. + /// The of values to subtract. + public static TensorSpan Subtract(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, ISubtractionOperators + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract); + } + + /// + /// Subtracts each element of from in place. + /// + /// The of values to be subtracted from. + /// The of values to subtract. + public static TensorSpan SubtractInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, ISubtractionOperators + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract, true); + } + #endregion + + #region Sum + /// + /// Sums all the elements of the and returns the result. + /// + /// The to sum. + public static T Sum(TensorSpan input) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + return TensorPrimitives.Sum(span); + } + #endregion + + #region Add + /// + /// Adds each element of to each element of and returns a new with the result. + /// + /// The first of elements to add. + /// The second of elements to add. + public static TensorSpan Add(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add); + } + + /// + /// Adds each element of to each element of in place. + /// + /// The first of values to add. + /// The second of values to add. + public static TensorSpan AddInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + { + return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add, true); + } + + /// + /// Adds to each element of and returns a new with the result. + /// + /// The of values to add. + /// The value to add to each element of . + public static TensorSpan Add(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Add(span, val, ospan); + return output; + } + + /// + /// Adds to each element of in place. + /// + /// The of values to add. + /// The value to add to each element of . + public static TensorSpan AddInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Add(span, val, ospan); + return output; + } + #endregion + + #region Norm + + /// + /// Takes the norm of the and returns the result. + /// + /// The to take the norm of. + public static T Norm(TensorSpan input) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + return TensorPrimitives.Norm(span); + } + #endregion + + #region Cos + /// + /// Takes the cosine of each element of the and returns a new with the result. + /// + /// The to take the cosine of. + public static TensorSpan Cos(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos); + } + + /// + /// Takes the cosine of each element of the in place. + /// + /// The to take the cosine of. + public static TensorSpan CosInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos, true); + } + #endregion + + #region Sin + + /// + /// Takes the sin of each element of the and returns a new with the result. + /// + /// The to take the sin of. + public static TensorSpan Sin(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin); + } + + /// + /// Takes the sin of each element of the in place. + /// + /// The to take the sin of. + public static TensorSpan SinInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin, true); + } + #endregion + + #region Sqrt + /// + /// Takes the square root of each element of the and returns a new with the result. + /// + /// The to take the square root of. + public static TensorSpan Sqrt(TensorSpan input) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt); + } + + /// + /// Takes the square root of each element of the in place. + /// + /// The to take the square root of. + public static TensorSpan SqrtInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt, true); + } + #endregion + + #region Log + + /// + /// Takes the natural logarithm of each element of the and returns a new with the result. + /// + /// The to take the natural logarithm of. + public static TensorSpan Log(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Log); + } + + /// + /// Takes the natural logarithm of each element of the in place. + /// + /// The to take the natural logarithm of. + public static TensorSpan LogInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Log, true); + } + #endregion + + #region Log10 + + /// + /// Takes the base 10 logarithm of each element of the and returns a new with the result. + /// + /// The to take the base 10 logarithm of. + public static TensorSpan Log10(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10); + } + + /// + /// Takes the base 10 logarithm of each element of the in place. + /// + /// The to take the base 10 logarithm of. + public static TensorSpan Log10InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10, true); + } + #endregion + + #region Log2 + /// + /// Takes the base 2 logarithm of each element of the and returns a new with the result. + /// + /// The to take the base 2 logarithm of. + public static TensorSpan Log2(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2); + } + + /// + /// Takes the base 2 logarithm of each element of the in place. + /// + /// The to take the base 2 logarithm of. + public static TensorSpan Log2InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2, true); + } + #endregion + + #region TensorPrimitivesHelpers + private delegate void PerformCalculationT1(ReadOnlySpan input, Span output) + where T : IEquatable, IEqualityOperators; + + private delegate void PerformCalculationT1T2(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output) + where T : IEquatable, IEqualityOperators; + + private static TensorSpan TensorPrimitivesHelperT1(TensorSpan input, PerformCalculationT1 performCalculation, bool inPlace = false) + where T : IEquatable, IEqualityOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = inPlace ? input : new TensorSpan(new T[input.FlattenedLength], 0, input.Lengths, input.Strides); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + performCalculation(span, ospan); + return output; + } + + private static TensorSpan TensorPrimitivesHelperT1T2(TensorSpan left, TensorSpan right, PerformCalculationT1T2 performCalculation, bool inPlace = false) + where T : IEquatable, IEqualityOperators + { + if (inPlace && left.Lengths != right.Lengths) + ThrowHelper.ThrowArgument_InPlaceInvalidShape(); + + //ReadOnlySpan span = MemoryMarshal.CreateSpan(ref tensor._reference, (int)tensor.FlattenedLength); + //ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); + //TensorSpan output = inPlace ? tensor : Create(tensor.IsPinned, tensor.Lengths); + //Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + //performCalculation(span, rspan, ospan); + //return output; + + TensorSpan output; + if (inPlace) + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref left._reference, (int)left.FlattenedLength); + ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); + output = left; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + performCalculation(span, rspan, ospan); + } + // If not in place but sizes are the same. + else if (left.Lengths.SequenceEqual(right.Lengths)) + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref left._reference, (int)left.FlattenedLength); + ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); + output = new TensorSpan(new T[left.FlattenedLength], 0, left.Lengths, left.Strides); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + performCalculation(span, rspan, ospan); + return output; + } + // Not in place and broadcasting needs to happen. + else + { + // Have a couple different possible cases here. + // 1 - Both tensors have row contiguous memory (i.e. a 1x5 being broadcast to a 5x5) + // 2 - One tensor has row contiguous memory and the right has column contiguous memory (i.e. a 1x5 and a 5x1) + + nint[] newSize = TensorHelpers.GetSmallestBroadcastableSize(left.Lengths, right.Lengths); + + TensorSpan broadcastedLeft = TensorSpan.BroadcastTo(left, newSize); + TensorSpan broadcastedRight = TensorSpan.BroadcastTo(right, newSize); + + output = new TensorSpan(new T[TensorSpanHelpers.CalculateTotalLength(newSize)], newSize, default); + nint rowLength = newSize[^1]; + Span ospan; + Span ispan; + Span buffer = new T[rowLength]; + + scoped Span curIndex; + nint[]? curIndexArray; + if (newSize.Length > 6) + { + curIndexArray = ArrayPool.Shared.Rent(newSize.Length); + curIndex = curIndexArray; + } + else + { + curIndexArray = null; + curIndex = stackalloc nint[newSize.Length]; + } + + int outputOffset = 0; + // ADD IN CASE WHERE NEITHER ARE ROW CONTIGUOUS + // tensor not row contiguous + if (broadcastedLeft.Strides[^1] == 0) + { + while (outputOffset < output.FlattenedLength) + { + ospan = MemoryMarshal.CreateSpan(ref Unsafe.Add(ref output._reference, outputOffset), (int)rowLength); + buffer.Fill(broadcastedLeft[curIndex]); + ispan = MemoryMarshal.CreateSpan(ref broadcastedRight[curIndex], (int)rowLength); + performCalculation(buffer, ispan, ospan); + outputOffset += (int)rowLength; + TensorSpanHelpers.AdjustIndexes(broadcastedLeft.Rank - 2, 1, curIndex, broadcastedLeft.Lengths); + } + } + // right not row contiguous + else if (broadcastedRight.Strides[^1] == 0) + { + while (outputOffset < output.FlattenedLength) + { + ospan = MemoryMarshal.CreateSpan(ref Unsafe.Add(ref output._reference, outputOffset), (int)rowLength); + buffer.Fill(broadcastedRight[curIndex]); + ispan = MemoryMarshal.CreateSpan(ref broadcastedLeft[curIndex], (int)rowLength); + performCalculation(ispan, buffer, ospan); + outputOffset += (int)rowLength; + TensorSpanHelpers.AdjustIndexes(broadcastedLeft.Rank - 2, 1, curIndex, broadcastedLeft.Lengths); + } + } + // both row contiguous + else + { + Span rspan; + while (outputOffset < output.FlattenedLength) + { + ospan = MemoryMarshal.CreateSpan(ref Unsafe.Add(ref output._reference, outputOffset), (int)rowLength); + ispan = MemoryMarshal.CreateSpan(ref broadcastedLeft[curIndex], (int)rowLength); + rspan = MemoryMarshal.CreateSpan(ref broadcastedRight[curIndex], (int)rowLength); + performCalculation(ispan, rspan, ospan); + outputOffset += (int)rowLength; + TensorSpanHelpers.AdjustIndexes(broadcastedLeft.Rank - 2, 1, curIndex, broadcastedLeft.Lengths); + } + } + + if (curIndexArray != null) + ArrayPool.Shared.Return(curIndexArray); + } + return output; + } + #endregion + #endregion } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs index 5a55bebba6b4c..2b2d62a58f9a5 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs @@ -1,13 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; -using System.Diagnostics; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Xml.Serialization; #pragma warning disable 8500 // sizeof of managed types diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs index d40726f4ab832..ed6e91c67cd19 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; +using System.Collections.Specialized; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using Microsoft.VisualBasic; #pragma warning disable 8500 // sizeof of managed types @@ -43,6 +40,34 @@ public static nint[] CalculateStrides(ReadOnlySpan lengths) { nint[] strides = new nint[lengths.Length]; + if (lengths.Length == 1 && lengths[0] == 0 || lengths.Length == 0) + { + strides[0] = 0; + return strides; + } + + nint stride = 1; + + for (int i = strides.Length - 1; i >= 0; i--) + { + strides[i] = stride; + stride *= lengths[i]; + } + + return strides; + } + + /// + /// Gets the set of strides that can be used to calculate the offset of n-dimensions in a 1-dimensional layout + /// + /// + public static nint[] CalculateStrides(ReadOnlySpan lengths, nint linearLength) + { + nint[] strides = new nint[lengths.Length]; + + if (linearLength == 0) + return strides; + nint stride = 1; for (int i = strides.Length - 1; i >= 0; i--) @@ -76,23 +101,63 @@ public static nint ComputeLinearIndex(ReadOnlySpan indexes, ReadOnlySpan strides, ReadOnlySpan lengths) + { + Debug.Assert(strides.Length == lengths.Length); + + nint index = 0; + for (int i = 0; i < lengths.Length; i++) + { + index += strides[i] * (lengths[i] - 1); + } + + return index; + } + /// /// Calculates the 1-d index for n-d indexes in layout specified by strides. /// + /// /// - /// - /// /// - public static nint ComputeLinearIndex(ReadOnlySpan indexes, ReadOnlySpan strides, ReadOnlySpan lengths) + public static nint ComputeStartOffsetSystemArray(Array array, ReadOnlySpan indexes) { - Debug.Assert(strides.Length == indexes.Length); + Debug.Assert(array.Rank == indexes.Length || indexes.Length == 0); - nint index = 0; - for (int i = 0; i < indexes.Length; i++) + if (indexes.Length == 0) + return 0; + + nint index = indexes[indexes.Length - 1]; + for (int i = indexes.Length - 2; i >= 0; i--) { - if (indexes[i] >= lengths[i] || indexes[i] < 0) + if ((indexes[i] != 0 && indexes[i] >= array.GetLength(i)) || indexes[i] < 0) ThrowHelper.ThrowIndexOutOfRangeException(); - index += strides[i] * indexes[i]; + index += array.GetLength(i) * indexes[i]; + } + + return index; + } + + /// + /// Calculates the 1-d index for n-d indexes in layout specified by strides. + /// + /// + /// + /// + public static nint ComputeStartOffsetSystemArray(Array array, ReadOnlySpan indexes) + { + Debug.Assert(array.Rank == indexes.Length || indexes.Length == 0); + + if (indexes.Length == 0) + return 0; + + nint index = indexes[indexes.Length - 1].GetOffset(array.GetLength(indexes.Length - 1)); + for (int i = indexes.Length - 2; i >= 0; i--) + { + nint offset = indexes[i].GetOffset(array.GetLength(i)); + if ((offset != 0 && offset >= array.GetLength(i)) || offset < 0) + ThrowHelper.ThrowIndexOutOfRangeException(); + index += array.GetLength(i) * offset; } return index; @@ -121,19 +186,25 @@ public static nint ComputeLinearIndex(ReadOnlySpan indexes, ReadOnlySpan return index; } - public static nint ComputeMaxElementCount(ReadOnlySpan strides, ReadOnlySpan lengths) + public static void ValidateStrides(ReadOnlySpan strides, ReadOnlySpan lengths) { Debug.Assert(strides.Length == lengths.Length); - nint index = 0; - for (int i = 0; i < lengths.Length; i++) + if (strides.Length == 0) + return; + + if (strides[lengths.Length - 1] < 0) + ThrowHelper.ThrowArgument_StrideLessThan0(); + + for (int i = lengths.Length - 1; i > 0; i--) { - if (strides[i] < 0) + if (strides[i - 1] == 0) + continue; + else if (strides[i - 1] < 0) + ThrowHelper.ThrowArgument_StrideLessThan0(); + if (strides[i - 1] < strides[i] * lengths[i]) ThrowHelper.ThrowArgument_StrideLessThan0(); - index *= strides[i] * lengths[i]; } - - return index; } /// diff --git a/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs b/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs index 520de436ac5f3..8cb4d7ab957dd 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs @@ -121,6 +121,12 @@ public static void ThrowArgument_1DTensorRequired(string? paramNames) throw new ArgumentException(SR.ThrowArgument_1DTensorRequired, paramNames); } + [DoesNotReturn] + public static void ThrowArgument_2DTensorRequired(string? paramNames) + { + throw new ArgumentException(SR.Argument_2DTensorRequired, paramNames); + } + [DoesNotReturn] public static void ThrowArgument_IncorrectNumberOfFilterItems(string? paramNames) { @@ -202,7 +208,13 @@ public static void ThrowArgument_InvalidStridesAndLengths() [DoesNotReturn] public static void ThrowArgument_StrideLessThan0() { - throw new ArgumentException(SR.ThrowArgument_StrideLessThan0); + throw new ArgumentOutOfRangeException(SR.ThrowArgument_StrideLessThan0); + } + + [DoesNotReturn] + internal static void ThrowArgument_IncompatibleDimensions(nint leftDim, nint rightDim) + { + throw new ArgumentException(SR.Format(SR.Argument_IncompatibleDimensions, leftDim, rightDim)); } } } diff --git a/src/libraries/System.Numerics.Tensors/tests/ReadOnlyTensorSpanTests.cs b/src/libraries/System.Numerics.Tensors/tests/ReadOnlyTensorSpanTests.cs index 918f011c3c16b..70161522e4882 100644 --- a/src/libraries/System.Numerics.Tensors/tests/ReadOnlyTensorSpanTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/ReadOnlyTensorSpanTests.cs @@ -2,6 +2,7 @@ // 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; @@ -12,6 +13,745 @@ namespace System.Numerics.Tensors.Tests { public class ReadOnlyTensorSpanTests { + [Fact] + public static void ReadOnlyTensorSpanSystemArrayConstructorTests() + { + // Make sure basic T[,] constructor works + int[,] a = new int[,] { { 91, 92, -93, 94 } }; + scoped ReadOnlyTensorSpan spanInt = new ReadOnlyTensorSpan(a); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(4, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[0, 2]); + Assert.Equal(94, spanInt[0, 3]); + + // Make sure null works + // Should be a tensor with 0 elements and Rank 0 and no strides or lengths + int[,] n = null; + spanInt = new ReadOnlyTensorSpan(n); + Assert.Equal(0, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths.Length); + Assert.Equal(0, spanInt.Strides.Length); + + // Make sure empty array works + // Should be a Tensor with 0 elements but Rank 2 with dimension 0 length 0 + int[,] b = { { } }; + spanInt = new ReadOnlyTensorSpan(b); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.Lengths[1]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + Assert.Equal(0, spanInt.Strides[1]); + // Make sure it still throws on index 0, 0 + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(b); + var x = spanInt[0, 0]; + }); + + // Make sure 2D array works + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [2, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure can use only some of the array + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[1, 1]; + }); + + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[0, -1]; + }); + + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[-1, 0]; + }); + + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[1, 0]; + }); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 1], [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 2], [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 3], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 3], [1, 2], default); + }); + + // Make sure 2D array works with basic strides + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 2], [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, 2], [-1, 0]); + }); + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, 2], [0, -1]); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [-1, 2], []); + }); + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[0, 0], [1, -2], []); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new ReadOnlyTensorSpan(a, (int[])[], [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => + { + var spanInt = new ReadOnlyTensorSpan(a, (int[])[], [2, 2], [1, 1]); + }); + + a = new int[,] { { 91, 92 }, { -93, 94 } }; + spanInt = new ReadOnlyTensorSpan(a, (int[])[1, 1], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + //Make sure it works with NIndex + spanInt = new ReadOnlyTensorSpan(a, (NIndex[])[1, 1], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + //Make sure it works with NIndex + spanInt = new ReadOnlyTensorSpan(a, (NIndex[])[^1, ^1], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + } + + [Fact] + public static void ReadOnlyTensorSpanArrayConstructorTests() + { + // Make sure basic T[] constructor works + int[] a = { 91, 92, -93, 94 }; + scoped ReadOnlyTensorSpan spanInt = new ReadOnlyTensorSpan(a); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(4, spanInt.Lengths[0]); + Assert.Equal(91, spanInt[0]); + Assert.Equal(92, spanInt[1]); + Assert.Equal(-93, spanInt[2]); + Assert.Equal(94, spanInt[3]); + + // Make sure null works + // Should be a tensor with 0 elements and Rank 0 and no strides or lengths + spanInt = new ReadOnlyTensorSpan(null); + Assert.Equal(0, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths.Length); + Assert.Equal(0, spanInt.Strides.Length); + + // Make sure empty array works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + int[] b = { }; + spanInt = new ReadOnlyTensorSpan(b); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + // Make sure it still throws on index 0 + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(b); + var x = spanInt[0]; + }); + + // Make sure empty array works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + spanInt = new ReadOnlyTensorSpan(b, 0, [], default); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + + // Make sure 2D array works + spanInt = new ReadOnlyTensorSpan(a, new Index(0), [2,2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0,0]); + Assert.Equal(92, spanInt[0,1]); + Assert.Equal(-93, spanInt[1,0]); + Assert.Equal(94, spanInt[1,1]); + + // Make sure can use only some of the array + spanInt = new ReadOnlyTensorSpan(a, new Index(0), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, new Index(0), [1, 2], default); + var x = spanInt[1, 1]; + }); + + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, new Index(0), [1, 2], default); + var x = spanInt[1, 0]; + }); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(a, new Index(1), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(a, new Index(2), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, new Index(3), [1, 2], default); + }); + + // Make sure 2D array works with basic strides + spanInt = new ReadOnlyTensorSpan(a, new Index(0), [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new ReadOnlyTensorSpan(a, new Index(0), [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new ReadOnlyTensorSpan(a, new Index(2), [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new ReadOnlyTensorSpan(a, new Index(3), [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, new Index(3), [1, 2], [-1, 0]); + }); + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, new Index(3), [1, 2], [0, -1]); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, new Index(3), [-1, 2], []); + }); + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, new Index(3), [1, -2], []); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new ReadOnlyTensorSpan(a, 0, [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => { + var spanInt = new ReadOnlyTensorSpan(a, 0, [2, 2], [1, 1]); + }); + } + + [Fact] + public static void ReadOnlyTensorSpanSpanConstructorTests() + { + // Make sure basic T[] constructor works + Span a = [ 91, 92, -93, 94 ]; + scoped ReadOnlyTensorSpan spanInt = new ReadOnlyTensorSpan(a); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(4, spanInt.Lengths[0]); + Assert.Equal(91, spanInt[0]); + Assert.Equal(92, spanInt[1]); + Assert.Equal(-93, spanInt[2]); + Assert.Equal(94, spanInt[3]); + + // Make sure empty span works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + Span b = []; + spanInt = new ReadOnlyTensorSpan(b); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + // Make sure it still throws on index 0 + Assert.Throws(() => { + Span b = []; + var spanInt = new ReadOnlyTensorSpan(b); + var x = spanInt[0]; + }); + + // Make sure 2D array works + spanInt = new ReadOnlyTensorSpan(a, [2, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure can use only some of the array + spanInt = new ReadOnlyTensorSpan(a, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a, [1, 2], default); + var x = spanInt[1, 1]; + }); + + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a, [1, 2], default); + var x = spanInt[1, 0]; + }); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(a.Slice(1), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(a.Slice(2), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a.Slice(3), [1, 2], default); + }); + + // Make sure 2D array works with basic strides + spanInt = new ReadOnlyTensorSpan(a, [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new ReadOnlyTensorSpan(a, [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new ReadOnlyTensorSpan(a.Slice(2), [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new ReadOnlyTensorSpan(a.Slice(3), [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a, [1, 2], [-1, 0]); + }); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a, [1, 2], [0, -1]); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a, [-1, 2], []); + }); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a, [1, -2], []); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new ReadOnlyTensorSpan(a, [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new ReadOnlyTensorSpan(a, [2, 2], [1, 1]); + }); + } + + [Fact] + public static unsafe void ReadOnlyTensorSpanPointerConstructorTests() + { + // Make sure basic T[] constructor works + Span a = [91, 92, -93, 94]; + ReadOnlyTensorSpan spanInt; + fixed (int* p = a) + { + spanInt = new ReadOnlyTensorSpan(p, 4); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(4, spanInt.Lengths[0]); + Assert.Equal(91, spanInt[0]); + Assert.Equal(92, spanInt[1]); + Assert.Equal(-93, spanInt[2]); + Assert.Equal(94, spanInt[3]); + } + + // Make sure empty span works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + Span b = []; + fixed (int* p = b) + { + spanInt = new ReadOnlyTensorSpan(p, 0); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + // Make sure it still throws on index 0 + Assert.Throws(() => + { + Span b = []; + fixed (int* p = b) + { + var spanInt = new ReadOnlyTensorSpan(p, 0); + var x = spanInt[0]; + } + }); + } + + + // Make sure 2D array works + fixed (int* p = a) + { + spanInt = new ReadOnlyTensorSpan(p, 4, [2, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure can use only some of the array + spanInt = new ReadOnlyTensorSpan(p, 4, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, 4, [1, 2], default); + var x = spanInt[1, 1]; + } + }); + + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, 4, [1, 2], default); + var x = spanInt[1, 0]; + } + }); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(p + 1, 3, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + + // Make sure Index offset works correctly + spanInt = new ReadOnlyTensorSpan(p + 2, 2, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p + 3, 1, [1, 2], default); + } + }); + + // Make sure 2D array works with basic strides + spanInt = new ReadOnlyTensorSpan(p, 4, [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new ReadOnlyTensorSpan(p, 4, [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new ReadOnlyTensorSpan(p + 2, 2, [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new ReadOnlyTensorSpan(p + 3, 1, [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, 4, [1, 2], [-1, 0]); + } + }); + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, 4, [1, 2], [0, -1]); + } + }); + + // Make sure lengths can't be negative + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, 4, [-1, 2], []); + } + }); + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, 4, [1, -2], []); + } + }); + + // Make sure can't use negative data length amount + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, -1, [1, -2], []); + } + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new ReadOnlyTensorSpan(p, 4, [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new ReadOnlyTensorSpan(p, 4, [2, 2], [1, 1]); + } + }); + } + } + [Fact] public static void IntArrayAsReadOnlyTensorSpan() { diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs index 911dc6805588a..e09b1a988cb1f 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs @@ -2,6 +2,7 @@ // 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.Reflection; @@ -14,13 +15,741 @@ namespace System.Numerics.Tensors.Tests public class TensorSpanTests { [Fact] - public static void ConstructorTests() + public static void TensorSpanSystemArrayConstructorTests() { - int[] a = [1, 2, 3]; - TensorSpan span = new TensorSpan(a, 0, [3, 3], [0, 1]); + // Make sure basic T[,] constructor works + int[,] a = new int[,] { { 91, 92, -93, 94 } }; + scoped TensorSpan spanInt = new TensorSpan(a); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(4, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[0, 2]); + Assert.Equal(94, spanInt[0, 3]); + + // Make sure null works + // Should be a tensor with 0 elements and Rank 0 and no strides or lengths + int[,] n = null; + spanInt = new TensorSpan(n); + Assert.Equal(0, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths.Length); + Assert.Equal(0, spanInt.Strides.Length); + + // Make sure empty array works + // Should be a Tensor with 0 elements but Rank 2 with dimension 0 length 0 + int[,] b = { { } }; + spanInt = new TensorSpan(b); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.Lengths[1]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + Assert.Equal(0, spanInt.Strides[1]); + // Make sure it still throws on index 0, 0 + Assert.Throws(() => { + var spanInt = new TensorSpan(b); + var x = spanInt[0, 0]; + }); + + // Make sure 2D array works + spanInt = new TensorSpan(a, (int[])[0, 0], [2, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure can use only some of the array + spanInt = new TensorSpan(a, (int[])[0, 0], [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[1, 1]; + }); + + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[0, -1]; + }); + + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[-1, 0]; + }); + + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [1, 2], default); + var x = spanInt[1, 0]; + }); + + // Make sure Index offset works correctly + spanInt = new TensorSpan(a, (int[])[0, 1], [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + + // Make sure Index offset works correctly + spanInt = new TensorSpan(a, (int[])[0, 2], [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new TensorSpan(a, (int[])[0, 3], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 3], [1, 2], default); + }); + + // Make sure 2D array works with basic strides + spanInt = new TensorSpan(a, (int[])[0, 0], [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new TensorSpan(a, (int[])[0, 0], [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new TensorSpan(a, (int[])[0, 2], [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [1, 2], [-1, 0]); + }); + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [1, 2], [0, -1]); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [-1, 2], []); + }); + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[0, 0], [1, -2], []); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new TensorSpan(a, (int[])[], [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => + { + var spanInt = new TensorSpan(a, (int[])[], [2, 2], [1, 1]); + }); + + a = new int[,] { { 91, 92 }, { -93, 94 } }; + spanInt = new TensorSpan(a, (int[])[1, 1], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + //Make sure it works with NIndex + spanInt = new TensorSpan(a, (NIndex[])[1, 1], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + //Make sure it works with NIndex + spanInt = new TensorSpan(a, (NIndex[])[^1, ^1], [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + } + + [Fact] + public static void TensorSpanArrayConstructorTests() + { + // Make sure basic T[] constructor works + int[] a = { 91, 92, -93, 94 }; + scoped TensorSpan spanInt = new TensorSpan(a); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(4, spanInt.Lengths[0]); + Assert.Equal(91, spanInt[0]); + Assert.Equal(92, spanInt[1]); + Assert.Equal(-93, spanInt[2]); + Assert.Equal(94, spanInt[3]); + + // Make sure null works + // Should be a tensor with 0 elements and Rank 0 and no strides or lengths + spanInt = new TensorSpan(null); + Assert.Equal(0, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths.Length); + Assert.Equal(0, spanInt.Strides.Length); + + // Make sure empty array works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + int[] b = { }; + spanInt = new TensorSpan(b); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + // Make sure it still throws on index 0 + Assert.Throws(() => { + var spanInt = new TensorSpan(b); + var x = spanInt[0]; + }); + + // Make sure empty array works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + spanInt = new TensorSpan(b, 0, [], default); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + + // Make sure 2D array works + spanInt = new TensorSpan(a, new Index(0), [2, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure can use only some of the array + spanInt = new TensorSpan(a, new Index(0), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => { + var spanInt = new TensorSpan(a, new Index(0), [1, 2], default); + var x = spanInt[1, 1]; + }); + + Assert.Throws(() => { + var spanInt = new TensorSpan(a, new Index(0), [1, 2], default); + var x = spanInt[1, 0]; + }); + + // Make sure Index offset works correctly + spanInt = new TensorSpan(a, new Index(1), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + + // Make sure Index offset works correctly + spanInt = new TensorSpan(a, new Index(2), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => { + var spanInt = new TensorSpan(a, new Index(3), [1, 2], default); + }); + + // Make sure 2D array works with basic strides + spanInt = new TensorSpan(a, new Index(0), [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new TensorSpan(a, new Index(0), [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new TensorSpan(a, new Index(2), [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new TensorSpan(a, new Index(3), [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => { + var spanInt = new TensorSpan(a, new Index(3), [1, 2], [-1, 0]); + }); + Assert.Throws(() => { + var spanInt = new TensorSpan(a, new Index(3), [1, 2], [0, -1]); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => { + var spanInt = new TensorSpan(a, new Index(3), [-1, 2], []); + }); + Assert.Throws(() => { + var spanInt = new TensorSpan(a, new Index(3), [1, -2], []); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new TensorSpan(a, 0, [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => { + var spanInt = new TensorSpan(a, 0, [2, 2], [1, 1]); + }); + } + + [Fact] + public static void TensorSpanSpanConstructorTests() + { + // Make sure basic T[] constructor works + Span a = [91, 92, -93, 94]; + scoped TensorSpan spanInt = new TensorSpan(a); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(4, spanInt.Lengths[0]); + Assert.Equal(91, spanInt[0]); + Assert.Equal(92, spanInt[1]); + Assert.Equal(-93, spanInt[2]); + Assert.Equal(94, spanInt[3]); + // Make sure empty span works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + Span b = []; + spanInt = new TensorSpan(b); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + // Make sure it still throws on index 0 + Assert.Throws(() => { + Span b = []; + var spanInt = new TensorSpan(b); + var x = spanInt[0]; + }); + // Make sure 2D array works + spanInt = new TensorSpan(a, [2, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure can use only some of the array + spanInt = new TensorSpan(a, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a, [1, 2], default); + var x = spanInt[1, 1]; + }); + + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a, [1, 2], default); + var x = spanInt[1, 0]; + }); + + // Make sure Index offset works correctly + spanInt = new TensorSpan(a.Slice(1), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + // Make sure Index offset works correctly + spanInt = new TensorSpan(a.Slice(2), [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a.Slice(3), [1, 2], default); + }); + + // Make sure 2D array works with basic strides + spanInt = new TensorSpan(a, [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new TensorSpan(a, [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new TensorSpan(a.Slice(2), [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new TensorSpan(a.Slice(3), [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a, [1, 2], [-1, 0]); + }); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a, [1, 2], [0, -1]); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a, [-1, 2], []); + }); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a, [1, -2], []); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new TensorSpan(a, [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var spanInt = new TensorSpan(a, [2, 2], [1, 1]); + }); + } + + [Fact] + public static unsafe void TensorSpanPointerConstructorTests() + { + // Make sure basic T[] constructor works + Span a = [91, 92, -93, 94]; + TensorSpan spanInt; + fixed (int* p = a) + { + spanInt = new TensorSpan(p, 4); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(4, spanInt.Lengths[0]); + Assert.Equal(91, spanInt[0]); + Assert.Equal(92, spanInt[1]); + Assert.Equal(-93, spanInt[2]); + Assert.Equal(94, spanInt[3]); + } + + // Make sure empty span works + // Should be a Tensor with 0 elements but Rank 1 with dimension 0 length 0 + Span b = []; + fixed (int* p = b) + { + spanInt = new TensorSpan(p, 0); + Assert.Equal(1, spanInt.Rank); + Assert.Equal(0, spanInt.Lengths[0]); + Assert.Equal(0, spanInt.FlattenedLength); + Assert.Equal(0, spanInt.Strides[0]); + // Make sure it still throws on index 0 + Assert.Throws(() => + { + Span b = []; + fixed (int* p = b) + { + var spanInt = new TensorSpan(p, 0); + var x = spanInt[0]; + } + }); + } + + // Make sure 2D array works + fixed (int* p = a) + { + spanInt = new TensorSpan(p, 4, [2, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure can use only some of the array + spanInt = new TensorSpan(p, 4, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, 4, [1, 2], default); + var x = spanInt[1, 1]; + } + }); + + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, 4, [1, 2], default); + var x = spanInt[1, 0]; + } + }); + + // Make sure Index offset works correctly + spanInt = new TensorSpan(p + 1, 3, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(92, spanInt[0, 0]); + Assert.Equal(-93, spanInt[0, 1]); + + // Make sure Index offset works correctly + spanInt = new TensorSpan(p + 2, 2, [1, 2], default); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(1, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + + // Make sure we catch that there aren't enough elements in the array for the lengths + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p + 3, 1, [1, 2], default); + } + }); + + // Make sure 2D array works with basic strides + spanInt = new TensorSpan(p, 4, [2, 2], [2, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + spanInt = new TensorSpan(p, 4, [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(92, spanInt[0, 1]); + Assert.Equal(91, spanInt[1, 0]); + Assert.Equal(92, spanInt[1, 1]); + + // Make sure 2D array works with stride of 0 and initial offset to loop over last 2 elements again + spanInt = new TensorSpan(p + 2, 2, [2, 2], [0, 1]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(-93, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure 2D array works with strides of all 0 and initial offset to loop over last element again + spanInt = new TensorSpan(p + 3, 1, [2, 2], [0, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(94, spanInt[0, 0]); + Assert.Equal(94, spanInt[0, 1]); + Assert.Equal(94, spanInt[1, 0]); + Assert.Equal(94, spanInt[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, 4, [1, 2], [-1, 0]); + } + }); + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, 4, [1, 2], [0, -1]); + } + }); + + // Make sure lengths can't be negative + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, 4, [-1, 2], []); + } + }); + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, 4, [1, -2], []); + } + }); + + // Make sure can't use negative data length amount + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, -1, [1, -2], []); + } + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + spanInt = new TensorSpan(p, 4, [2, 2], [2, 0]); + Assert.Equal(2, spanInt.Rank); + Assert.Equal(2, spanInt.Lengths[0]); + Assert.Equal(2, spanInt.Lengths[1]); + Assert.Equal(91, spanInt[0, 0]); + Assert.Equal(91, spanInt[0, 1]); + Assert.Equal(-93, spanInt[1, 0]); + Assert.Equal(-93, spanInt[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => + { + Span a = [91, 92, -93, 94]; + fixed (int* p = a) + { + var spanInt = new TensorSpan(p, 4, [2, 2], [1, 1]); + } + }); + } } [Fact] diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs index 822469f3c4a4c..f5f61cf936856 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs @@ -13,6 +13,311 @@ namespace System.Numerics.Tensors.Tests { public class TensorTests { + [Fact] + public static void TensorFactoryCreateUninitializedTests() + { + // Basic tensor creation + Tensor t1 = Tensor.CreateUninitialized([1]); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(1, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(1, t1.Strides[0]); + Assert.False(t1.IsPinned); + + // Make sure can't index too many dimensions + Assert.Throws(() => + { + var x = t1[1, 1]; + }); + + // Make sure can't index beyond end + Assert.Throws(() => + { + var x = t1[1]; + }); + + // Make sure can't index negative index + Assert.Throws(() => + { + var x = t1[-1]; + }); + + // Make sure lengths can't be negative + Assert.Throws(() => + { + Tensor t1 = Tensor.CreateUninitialized([-1]); + }); + + t1 = Tensor.CreateUninitialized([0]); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(0, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(0, t1.Strides[0]); + Assert.False(t1.IsPinned); + + t1 = Tensor.CreateUninitialized([]); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(0, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(0, t1.Strides[0]); + Assert.False(t1.IsPinned); + + // Null should behave like empty array since there is no "null" span. + t1 = Tensor.CreateUninitialized(null); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(0, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(0, t1.Strides[0]); + Assert.False(t1.IsPinned); + + // Make sure pinned works + t1 = Tensor.CreateUninitialized([1], true); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(1, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(1, t1.Strides[0]); + Assert.True(t1.IsPinned); + + // Make sure 2D array works with basic strides + t1 = Tensor.CreateUninitialized([2, 2], [2, 1]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + // Can't validate actual values since it's uninitialized + // So by checking the type we assert no errors were thrown + Assert.IsType(t1[0, 0]); + Assert.IsType(t1[0, 1]); + Assert.IsType(t1[1, 0]); + Assert.IsType(t1[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + t1 = Tensor.CreateUninitialized([2, 2], [0, 1]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + // Can't validate actual values since it's uninitialized + // But since it loops over the first 2 elements we can assert the results are the same for those. + Assert.Equal(t1[0, 0], t1[1, 0]); + Assert.Equal(t1[0, 1], t1[1, 1]); + + // Make sure 2D array works with strides of all 0 to loop over first element again + t1 = Tensor.CreateUninitialized([2, 2], [0, 0]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + // Can't validate actual values since it's uninitialized + // But since it loops over the first element we can assert the results are the same. + Assert.Equal(t1[0, 0], t1[0, 1]); + Assert.Equal(t1[0, 0], t1[1, 0]); + Assert.Equal(t1[0, 0], t1[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => { + var t1 = Tensor.CreateUninitialized([1, 2], [-1, 0], false); + }); + Assert.Throws(() => { + var t1 = Tensor.CreateUninitialized([1, 2], [0, -1], false); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => { + var t1 = Tensor.CreateUninitialized([-1, 2], [], false); + }); + Assert.Throws(() => { + var t1 = Tensor.CreateUninitialized([1, -2], [], false); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + t1 = Tensor.CreateUninitialized([2, 2], [2, 0]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + Assert.Equal(t1[0, 0], t1[0, 1]); + Assert.Equal(t1[1, 0], t1[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => { + var t1 = Tensor.CreateUninitialized([2, 2], [1, 1], false); + }); + } + + [Fact] + public static void TensorFactoryCreateTests() + { + // Basic tensor creation + Tensor t1 = Tensor.Create([1]); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(1, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(1, t1.Strides[0]); + Assert.False(t1.IsPinned); + Assert.Equal(0, t1[0]); + + // Make sure can't index too many dimensions + Assert.Throws(() => + { + var x = t1[1, 1]; + }); + + // Make sure can't index beyond end + Assert.Throws(() => + { + var x = t1[1]; + }); + + // Make sure can't index negative index + Assert.Throws(() => + { + var x = t1[-1]; + }); + + // Make sure lengths can't be negative + Assert.Throws(() => + { + Tensor t1 = Tensor.Create([-1]); + }); + + t1 = Tensor.Create([0]); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(0, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(0, t1.Strides[0]); + Assert.False(t1.IsPinned); + + t1 = Tensor.Create([]); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(0, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(0, t1.Strides[0]); + Assert.False(t1.IsPinned); + + // Null should behave like empty array since there is no "null" span. + t1 = Tensor.Create(null); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(0, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(0, t1.Strides[0]); + Assert.False(t1.IsPinned); + + // Make sure pinned works + t1 = Tensor.Create([1], true); + Assert.Equal(1, t1.Rank); + Assert.Equal(1, t1.Lengths.Length); + Assert.Equal(1, t1.Lengths[0]); + Assert.Equal(1, t1.Strides.Length); + Assert.Equal(1, t1.Strides[0]); + Assert.True(t1.IsPinned); + Assert.Equal(0, t1[0]); + + int[] a = [91, 92, -93, 94]; + // Make sure 2D array works with basic strides + t1 = Tensor.Create(a, [2, 2], [2, 1]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + Assert.Equal(91, t1[0, 0]); + Assert.Equal(92, t1[0, 1]); + Assert.Equal(-93, t1[1, 0]); + Assert.Equal(94, t1[1, 1]); + + // Make sure 2D array works with stride of 0 to loop over first 2 elements again + t1 = Tensor.Create(a, [2, 2], [0, 1]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + Assert.Equal(91, t1[0, 0]); + Assert.Equal(92, t1[0, 1]); + Assert.Equal(91, t1[1, 0]); + Assert.Equal(92, t1[1, 1]); + + // Make sure 2D array works with strides of all 0 to loop over first element again + t1 = Tensor.Create(a, [2, 2], [0, 0]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + Assert.Equal(91, t1[0, 0]); + Assert.Equal(91, t1[0, 1]); + Assert.Equal(91, t1[1, 0]); + Assert.Equal(91, t1[1, 1]); + + // Make sure 2D array works with strides of all 0 only 1 element to make sure it doesn't leave that element + t1 = Tensor.Create([a[3]], [2, 2], [0, 0]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + Assert.Equal(94, t1[0, 0]); + Assert.Equal(94, t1[0, 1]); + Assert.Equal(94, t1[1, 0]); + Assert.Equal(94, t1[1, 1]); + + // Make sure strides can't be negative + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var t1 = Tensor.Create([1, 2], [-1, 0], false); + }); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var t1 = Tensor.Create([1, 2], [0, -1], false); + }); + + // Make sure lengths can't be negative + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var t1 = Tensor.Create([-1, 2], [], false); + }); + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var t1 = Tensor.Create([1, -2], [], false); + }); + + // Make sure 2D array works with strides to hit element 0,0,2,2 + t1 = Tensor.Create(a, [2, 2], [2, 0]); + Assert.Equal(2, t1.Rank); + Assert.Equal(2, t1.Lengths[0]); + Assert.Equal(2, t1.Lengths[1]); + Assert.Equal(91, t1[0, 0]); + Assert.Equal(91, t1[0, 1]); + Assert.Equal(-93, t1[1, 0]); + Assert.Equal(-93, t1[1, 1]); + + // Make sure you can't overlap elements using strides + Assert.Throws(() => { + Span a = [91, 92, -93, 94]; + var t1 = Tensor.Create([2, 2], [1, 1], false); + }); + } + + [Fact] + public static void TensorCosineSimilarityTests() + { + float[] a = [0, 0, 0, 1, 1, 1]; + float[] b = [1, 0, 0, 1, 1, 0]; + + Tensor left = Tensor.Create(a, [2,3]); + Tensor right = Tensor.Create(b, [2,3]); + + Tensor result = Tensor.CosineSimilarity(left, right); + Assert.Equal(2, result.Rank); + Assert.Equal(2, result.Lengths[0]); + Assert.Equal(2, result.Lengths[1]); + + + Assert.Equal(float.NaN, result[0, 0]); + Assert.Equal(float.NaN, result[0, 1]); + + Assert.Equal(0.57735, result[1, 0], .00001); + Assert.Equal(0.81649, result[1, 1], .00001); + } + [Fact] public static void TensorSequenceEqualTests() { @@ -823,10 +1128,10 @@ public static void TensorPermuteTests() public static void IntArrayAsTensor() { int[] a = [91, 92, -93, 94]; - TensorSpan spanInt = a.AsTensorSpan(4); + TensorSpan t1 = a.AsTensorSpan(4); nint[] dims = [4]; var tensor = Tensor.CreateUninitialized(dims.AsSpan(), false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); Assert.Equal(1, tensor.Rank); Assert.Equal(1, tensor.Lengths.Length); @@ -852,13 +1157,13 @@ public static void IntArrayAsTensor() a[1] = 92; a[2] = -93; a[3] = 94; - spanInt = a.AsTensorSpan(2, 2); + t1 = a.AsTensorSpan(2, 2); dims = [2, 2]; tensor = Tensor.CreateUninitialized(dims.AsSpan(), false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); Assert.Equal(a, tensor.ToArray()); Assert.Equal(2, tensor.Rank); - //Assert.Equal(4, spanInt.FlattenedLength); + //Assert.Equal(4, t1.FlattenedLength); Assert.Equal(2, tensor.Lengths.Length); Assert.Equal(2, tensor.Lengths[0]); Assert.Equal(2, tensor.Lengths[1]); @@ -957,9 +1262,9 @@ public static void TensorFillTest() public static void TensorClearTest() { int[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - TensorSpan spanInt = a.AsTensorSpan(3, 3); + TensorSpan t1 = a.AsTensorSpan(3, 3); var tensor = Tensor.CreateUninitialized([3, 3], false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); var slice = tensor.Slice(0..2, 0..2); slice.Clear(); Assert.Equal(0, slice[0, 0]); @@ -987,9 +1292,9 @@ public static void TensorClearTest() } a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - spanInt = a.AsTensorSpan(9); + t1 = a.AsTensorSpan(9); tensor = Tensor.CreateUninitialized([9], false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); slice = tensor.Slice(0..1); slice.Clear(); Assert.Equal(0, slice[0]); @@ -1014,9 +1319,9 @@ public static void TensorClearTest() } a = [.. Enumerable.Range(0, 27)]; - spanInt = a.AsTensorSpan(3, 3, 3); + t1 = a.AsTensorSpan(3, 3, 3); tensor = Tensor.CreateUninitialized([3, 3, 3], false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); tensor.Clear(); enumerator = tensor.GetEnumerator(); while (enumerator.MoveNext()) @@ -1025,9 +1330,9 @@ public static void TensorClearTest() } a = [.. Enumerable.Range(0, 12)]; - spanInt = a.AsTensorSpan(3, 2, 2); + t1 = a.AsTensorSpan(3, 2, 2); tensor = Tensor.CreateUninitialized([3, 2, 2], false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); tensor.Clear(); enumerator = tensor.GetEnumerator(); while (enumerator.MoveNext()) @@ -1036,9 +1341,9 @@ public static void TensorClearTest() } a = [.. Enumerable.Range(0, 16)]; - spanInt = a.AsTensorSpan(2, 2, 2, 2); + t1 = a.AsTensorSpan(2, 2, 2, 2); tensor = Tensor.CreateUninitialized([2, 2, 2, 2], false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); tensor.Clear(); enumerator = tensor.GetEnumerator(); while (enumerator.MoveNext()) @@ -1047,9 +1352,9 @@ public static void TensorClearTest() } a = [.. Enumerable.Range(0, 24)]; - spanInt = a.AsTensorSpan(3, 2, 2, 2); + t1 = a.AsTensorSpan(3, 2, 2, 2); tensor = Tensor.CreateUninitialized([3, 2, 2, 2], false); - spanInt.CopyTo(tensor); + t1.CopyTo(tensor); tensor.Clear(); enumerator = tensor.GetEnumerator(); while (enumerator.MoveNext()) @@ -1059,8 +1364,8 @@ public static void TensorClearTest() // Make sure clearing a slice of a SPan doesn't clear the whole thing. a = [.. Enumerable.Range(0, 9)]; - spanInt = a.AsTensorSpan(3, 3); - var spanSlice = spanInt.Slice(0..1, 0..3); + t1 = a.AsTensorSpan(3, 3); + var spanSlice = t1.Slice(0..1, 0..3); spanSlice.Clear(); var spanEnumerator = spanSlice.GetEnumerator(); while (spanEnumerator.MoveNext()) @@ -1068,20 +1373,20 @@ public static void TensorClearTest() Assert.Equal(0, spanEnumerator.Current); } - Assert.Equal(0, spanInt[0, 0]); - Assert.Equal(0, spanInt[0, 1]); - Assert.Equal(0, spanInt[0, 2]); - Assert.Equal(3, spanInt[1, 0]); - Assert.Equal(4, spanInt[1, 1]); - Assert.Equal(5, spanInt[1, 2]); - Assert.Equal(6, spanInt[2, 0]); - Assert.Equal(7, spanInt[2, 1]); - Assert.Equal(8, spanInt[2, 2]); + Assert.Equal(0, t1[0, 0]); + Assert.Equal(0, t1[0, 1]); + Assert.Equal(0, t1[0, 2]); + Assert.Equal(3, t1[1, 0]); + Assert.Equal(4, t1[1, 1]); + Assert.Equal(5, t1[1, 2]); + Assert.Equal(6, t1[2, 0]); + Assert.Equal(7, t1[2, 1]); + Assert.Equal(8, t1[2, 2]); // Make sure clearing a slice from the middle of a SPan doesn't clear the whole thing. a = [.. Enumerable.Range(0, 9)]; - spanInt = a.AsTensorSpan(3, 3); - spanSlice = spanInt.Slice(1..2, 0..3); + t1 = a.AsTensorSpan(3, 3); + spanSlice = t1.Slice(1..2, 0..3); spanSlice.Clear(); spanEnumerator = spanSlice.GetEnumerator(); while (spanEnumerator.MoveNext()) @@ -1089,20 +1394,20 @@ public static void TensorClearTest() Assert.Equal(0, spanEnumerator.Current); } - Assert.Equal(0, spanInt[0, 0]); - Assert.Equal(1, spanInt[0, 1]); - Assert.Equal(2, spanInt[0, 2]); - Assert.Equal(0, spanInt[1, 0]); - Assert.Equal(0, spanInt[1, 1]); - Assert.Equal(0, spanInt[1, 2]); - Assert.Equal(6, spanInt[2, 0]); - Assert.Equal(7, spanInt[2, 1]); - Assert.Equal(8, spanInt[2, 2]); + Assert.Equal(0, t1[0, 0]); + Assert.Equal(1, t1[0, 1]); + Assert.Equal(2, t1[0, 2]); + Assert.Equal(0, t1[1, 0]); + Assert.Equal(0, t1[1, 1]); + Assert.Equal(0, t1[1, 2]); + Assert.Equal(6, t1[2, 0]); + Assert.Equal(7, t1[2, 1]); + Assert.Equal(8, t1[2, 2]); // Make sure clearing a slice from the end of a SPan doesn't clear the whole thing. a = [.. Enumerable.Range(0, 9)]; - spanInt = a.AsTensorSpan(3, 3); - spanSlice = spanInt.Slice(2..3, 0..3); + t1 = a.AsTensorSpan(3, 3); + spanSlice = t1.Slice(2..3, 0..3); spanSlice.Clear(); spanEnumerator = spanSlice.GetEnumerator(); while (spanEnumerator.MoveNext()) @@ -1110,15 +1415,15 @@ public static void TensorClearTest() Assert.Equal(0, spanEnumerator.Current); } - Assert.Equal(0, spanInt[0, 0]); - Assert.Equal(1, spanInt[0, 1]); - Assert.Equal(2, spanInt[0, 2]); - Assert.Equal(3, spanInt[1, 0]); - Assert.Equal(4, spanInt[1, 1]); - Assert.Equal(5, spanInt[1, 2]); - Assert.Equal(0, spanInt[2, 0]); - Assert.Equal(0, spanInt[2, 1]); - Assert.Equal(0, spanInt[2, 2]); + Assert.Equal(0, t1[0, 0]); + Assert.Equal(1, t1[0, 1]); + Assert.Equal(2, t1[0, 2]); + Assert.Equal(3, t1[1, 0]); + Assert.Equal(4, t1[1, 1]); + Assert.Equal(5, t1[1, 2]); + Assert.Equal(0, t1[2, 0]); + Assert.Equal(0, t1[2, 1]); + Assert.Equal(0, t1[2, 2]); // Make sure it works with reference types. object[] o = [new object(), new object(), new object(), new object(), new object(), new object(), new object(), new object(), new object()]; From fa2c59a3209c9ce5933c895d491b4da6d7a2755d Mon Sep 17 00:00:00 2001 From: Michael Sharp Date: Mon, 3 Jun 2024 11:44:30 -0600 Subject: [PATCH 2/5] TensorSpan extensions --- .../Tensors/netcore/TensorExtensions.cs | 26 +- .../Tensors/netcore/TensorSpanExtensions.cs | 1946 ++++++++++++++--- 2 files changed, 1703 insertions(+), 269 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs index b5b7e5a89cede..ca9901492f7ff 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs @@ -1336,11 +1336,7 @@ public static Tensor AddInPlace(Tensor left, Tensor right) public static Tensor Add(Tensor input, T val) where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = Create(input.Lengths, input.IsPinned); - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInTInSpanOut(input, val, TensorPrimitives.Add); } /// @@ -1351,11 +1347,8 @@ public static Tensor Add(Tensor input, T val) public static Tensor AddInPlace(Tensor input, T val) where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); - Tensor output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInTInSpanOut(input, val, TensorPrimitives.Add, true); + } #endregion @@ -2990,6 +2983,9 @@ private delegate void PerformCalculationTFromSpanInTToSpanOut(ReadOn where TFrom : IEquatable, IEqualityOperators, INumberBase where TTo : INumberBase; + private delegate void PerformCalculationSpanInTInSpanOut(ReadOnlySpan input, T value, Span output) + where T : IEquatable, IEqualityOperators; + private delegate void PerformCalculationSpanInSpanOut(ReadOnlySpan input, Span output) where T : IEquatable, IEqualityOperators; @@ -3005,6 +3001,16 @@ private delegate T PerformCalculationSpanInTOut(ReadOnlySpan input) private delegate void PerformCalculationTwoSpanInSpanOut(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output) where T : IEquatable, IEqualityOperators; + private static Tensor TensorPrimitivesHelperSpanInTInSpanOut(Tensor input, T value, PerformCalculationSpanInTInSpanOut performCalculation, bool inPlace = false) + where T : IEquatable, IEqualityOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Tensor output = inPlace ? input : Create(input.Lengths, input.IsPinned); + Span ospan = MemoryMarshal.CreateSpan(ref output._values[0], (int)output._flattenedLength); + performCalculation(span, value, ospan); + return output; + } + private static Tensor TensorPrimitivesHelperSpanInIntSpanOut(Tensor input, PerformCalculationSpanInIntSpanOut performCalculation) where T : IEquatable, IEqualityOperators { diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs index aa975e04907b7..5135dac23ee5c 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; +using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -81,6 +82,39 @@ public static string ToString(this ReadOnlyTensorSpan span, params scoped } #endregion + #region Broadcast + /// + /// Broadcast the data from to the smallest broadcastable shape compatible with . Creates a new and allocates new memory. + /// + /// Input . + /// Other to make shapes broadcastable. + public static TensorSpan Broadcast(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators + { + nint[] newSize = TensorHelpers.GetSmallestBroadcastableSize(left.Lengths, right.Lengths); + + TensorSpan intermediate = BroadcastTo(left, newSize); + T[] data = new T[intermediate.FlattenedLength]; + intermediate.FlattenTo(data); + return new TensorSpan(data, 0, intermediate.Lengths, []); + } + + /// + /// Broadcast the data from to the new shape . Creates a new and allocates new memory. + /// If the shape of the is not compatible with the new shape, an exception is thrown. + /// + /// Input . + /// of the desired new shape. + /// Thrown when the shapes are not broadcast compatible. + public static TensorSpan Broadcast(TensorSpan input, scoped ReadOnlySpan shape) + where T : IEquatable, IEqualityOperators + { + TensorSpan intermediate = BroadcastTo(input, shape); + T[] data = new T[intermediate.FlattenedLength]; + intermediate.FlattenTo(data); + return new TensorSpan(data, 0, intermediate.Lengths, []); + } + // Lazy/non-copy broadcasting, internal only for now. /// /// Broadcast the data from to the new shape . Creates a new @@ -124,7 +158,9 @@ internal static TensorSpan BroadcastTo(TensorSpan input, scoped ReadOnl return output; } + #endregion + #region Reverse /// /// Reverse the order of elements in the along the given axis. The shape of the tensor is preserved, but the elements are reordered. /// defaults to -1 when not provided, which reverses the entire span. @@ -197,7 +233,9 @@ public static TensorSpan Reverse(TensorSpan input, nint axis = -1) return input; } + #endregion + #region Reshape /// /// Reshapes the tensor to the specified . If one of the lengths is -1, it will be calculated automatically. /// Does not change the length of the underlying memory nor does it allocate new memory. If the new shape is not compatible with the old shape, @@ -232,339 +270,1460 @@ public static TensorSpan Reshape(this TensorSpan input, params scoped R nint[] strides = TensorSpanHelpers.CalculateStrides(arrLengths); return new TensorSpan(ref input._reference, arrLengths, strides, input._memoryLength); } + #endregion #region TensorPrimitives - #region Multiply + #region Abs /// - /// Multiplies each element of with and returns a new with the result. + /// Takes the absolute value of each element of the and returns a new with the result. /// - /// Input - /// value to multiply by. - public static TensorSpan Multiply(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static TensorSpan Abs(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Multiply(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs); } /// - /// Multiplies each element of with in place. + /// Takes the absolute of each element of the in place. /// - /// Input - /// value to multiply by. - public static TensorSpan MultiplyInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static TensorSpan AbsInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Multiply(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs, true); } + #endregion + #region Acos /// - /// Multiplies each element of with and returns a new with the result. - /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Takes the inverse cosine of each element of the and returns a new with the result. /// - /// Left for multiplication. - /// Right for multiplication. - public static TensorSpan Multiply(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static TensorSpan Acos(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acos); } /// - /// Multiplies each element of with in place. - /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Takes the inverse cosine of each element of the in place. /// - /// Left for multiplication. - /// Right for multiplication. - public static TensorSpan MultiplyInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + /// The to take the sin of. + public static TensorSpan AcosInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Multiply, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acos, true); } #endregion - #region Divide + #region Acosh /// - /// Divides each element of by and returns a new with the result. + /// Takes the inverse hyperbolic cosine of each element of the and returns a new with the result. /// - /// Input . - /// The divisor - public static TensorSpan Divide(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static TensorSpan Acosh(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acosh); } /// - /// Divides each element of by in place. + /// Takes the inverse hyperbolic cosine of each element of the in place. /// - /// Input . - /// The divisor - public static TensorSpan DivideInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static TensorSpan AcoshInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Acosh, true); } + #endregion + #region AcosPi /// - /// Divides by each element of and returns a new with the result."/> + /// Takes the inverse hyperbolic cosine divided by pi of each element of the and returns a new with the result. /// - /// The value to be divided. - /// The divisor. - public static TensorSpan Divide(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static TensorSpan AcosPi(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(val, span, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AcosPi); } /// - /// Divides by each element of in place. + /// Takes the inverse hyperbolic cosine divided by pi of each element of the in place. /// - /// The value to be divided. - /// The divisor. - public static TensorSpan DivideInPlace(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The to take the sin of. + public static TensorSpan AcosPiInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Divide(val, span, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AcosPi, true); } + #endregion + #region Add /// - /// Divides each element of by its corresponding element in and returns - /// a new with the result. + /// Adds each element of to each element of and returns a new with the result. /// - /// The to be divided. - /// The divisor. - public static TensorSpan Divide(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The of values to add. + /// The second of values to add. + public static TensorSpan Add(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Add); } /// - /// Divides each element of by its corresponding element in in place. + /// Adds each element of to each element of in place. /// - /// The to be divided. - /// The divisor. - public static TensorSpan DivideInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IDivisionOperators + /// The of values to add. + /// The second of values to add. + public static TensorSpan AddInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Divide, true); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Add, true); } - #endregion - #region Subtract /// - /// Subtracts from each element of and returns a new with the result. + /// Adds to each element of and returns a new with the result. /// - /// The with values to be subtracted from. - /// The value to subtract. - public static TensorSpan Subtract(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The of values to add. + /// The to add to each element of . + public static TensorSpan Add(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInTInSpanOut(input, val, TensorPrimitives.Add); } /// - /// Subtracts from each element of in place. + /// Adds to each element of in place. /// - /// The with values to be subtracted from. - /// The value to subtract. - public static TensorSpan SubtractInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The of values to add. + /// The to add to each element of . + public static TensorSpan AddInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInTInSpanOut(input, val, TensorPrimitives.Add, true); + } + #endregion + #region Asin /// - /// Subtracts each element of from and returns a new with the result. + /// Takes the inverse sin of each element of the and returns a new with the result. /// - /// The value to be subtracted from. - /// The values to subtract. - public static TensorSpan Subtract(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The to take the sin of. + public static TensorSpan Asin(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(val, span, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asin); } /// - /// Subtracts each element of from in place. + /// Takes the inverse sine each element of the in place. /// - /// The value to be subtracted from. - /// The values to subtract. - public static TensorSpan SubtractInPlace(T val, TensorSpan input) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The to take the sin of. + public static TensorSpan AsinInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Subtract(val, span, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asin, true); } + #endregion + #region Asinh /// - /// Subtracts each element of from and returns a new with the result. + /// Takes the inverse hyperbolic sine of each element of the and returns a new with the result. /// - /// The of values to be subtracted from. - /// The of values to subtract. - public static TensorSpan Subtract(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The to take the sin of. + public static TensorSpan Asinh(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asinh); } /// - /// Subtracts each element of from in place. + /// Takes the inverse hyperbolic sine each element of the in place. /// - /// The of values to be subtracted from. - /// The of values to subtract. - public static TensorSpan SubtractInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, ISubtractionOperators + /// The to take the sin of. + public static TensorSpan AsinhInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Subtract, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Asinh, true); } #endregion - #region Sum + #region AsinPi /// - /// Sums all the elements of the and returns the result. + /// Takes the inverse hyperbolic sine divided by pi of each element of the and returns a new with the result. /// - /// The to sum. - public static T Sum(TensorSpan input) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The to take the sin of. + public static TensorSpan AsinPi(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - return TensorPrimitives.Sum(span); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AsinPi); } - #endregion - #region Add /// - /// Adds each element of to each element of and returns a new with the result. + /// Takes the inverse hyperbolic sine divided by pi of each element of the in place. /// - /// The first of elements to add. - /// The second of elements to add. - public static TensorSpan Add(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The to take the sin of. + public static TensorSpan AsinPiInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AsinPi, true); } + #endregion + #region Atan /// - /// Adds each element of to each element of in place. + /// Takes the arc tangent of each element of the and returns a new with the result. /// - /// The first of values to add. - /// The second of values to add. - public static TensorSpan AddInPlace(TensorSpan left, TensorSpan right) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The input + public static TensorSpan Atan(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1T2(left, right, TensorPrimitives.Add, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atan); } /// - /// Adds to each element of and returns a new with the result. + /// Takes the arc tangent of each element of the in place. /// - /// The of values to add. - /// The value to add to each element of . - public static TensorSpan Add(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The input + public static TensorSpan AtanInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - T[] values = new T[input.FlattenedLength]; - TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atan, true); } + #endregion + #region Atan2 /// - /// Adds to each element of in place. + /// Takes the arc tangent of the two input and returns a new with the result. /// - /// The of values to add. - /// The value to add to each element of . - public static TensorSpan AddInPlace(TensorSpan input, T val) - where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + /// The left . + /// The right . + public static TensorSpan Atan2(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - TensorSpan output = input; - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - TensorPrimitives.Add(span, val, ospan); - return output; + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2); } - #endregion - - #region Norm /// - /// Takes the norm of the and returns the result. + /// Takes the arc tangent of the two input in place. /// - /// The to take the norm of. - public static T Norm(TensorSpan input) - where T : IEquatable, IEqualityOperators, IRootFunctions + /// The left . + /// The right . + public static TensorSpan Atan2InPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - return TensorPrimitives.Norm(span); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2, true); } #endregion - #region Cos + #region Atan2Pi /// - /// Takes the cosine of each element of the and returns a new with the result. + /// Takes the arc tangent of the two input , divides each element by pi, and returns a new with the result. + /// + /// The left . + /// The right . + public static TensorSpan Atan2Pi(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2Pi); + } + + /// + /// Takes the arc tangent of the two input , divides each element by pi in place. + /// + /// The left . + /// The right . + public static TensorSpan Atan2PiInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Atan2Pi, true); + } + #endregion + + #region Atanh + /// + /// Takes the inverse hyperbolic tangent of each element of the and returns a new with the result. + /// + /// The input . + public static TensorSpan Atanh(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atanh); + } + + /// + /// Takes the inverse hyperbolic tangent of each element of the in place. + /// + /// The input . + public static TensorSpan AtanhInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Atanh, true); + } + #endregion + + #region AtanPi + /// + /// Takes the inverse hyperbolic tangent divided by pi of each element of the and returns a new with the result. + /// + /// The input. + public static TensorSpan AtanPi(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AtanPi); + } + + /// + /// Takes the inverse hyperbolic tangent divided by pi of each element of the in place. + /// + /// The input. + public static TensorSpan AtanPiInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.AtanPi, true); + } + #endregion + + #region BitwiseAnd + /// + /// Computes the element-wise bitwise and of the two input and returns a new with the result. + /// + /// The left . + /// The right . + public static TensorSpan BitwiseAnd(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseAnd); + } + + /// + /// Computes the element-wise bitwise and of the two input in place. + /// + /// The left . + /// The right . + public static TensorSpan BitwiseAndInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseAnd, true); + } + #endregion + + #region BitwiseOr + /// + /// Computes the element-wise bitwise of of the two input and returns a new with the result. + /// + /// The left . + /// The right . + public static TensorSpan BitwiseOr(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseOr); + } + + /// + /// Computes the element-wise bitwise of of the two input in place. + /// + /// The left . + /// The right . + public static TensorSpan BitwiseOrInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.BitwiseOr, true); + } + #endregion + + #region CubeRoot + /// + /// Computes the element-wise cube root of the input and returns a new with the result. + /// + /// The left . + public static TensorSpan CubeRoot(TensorSpan input) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cbrt); + } + + /// + /// Computes the element-wise cube root of the input in place. + /// + /// The left . + public static TensorSpan CubeRootInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cbrt, true); + } + #endregion + + #region Ceiling + /// + /// Computes the element-wise ceiling of the input and returns a new with the result. + /// + /// The left . + public static TensorSpan Ceiling(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Ceiling); + } + + /// + /// Computes the element-wise ceiling of the input in place. + /// + /// The left . + public static TensorSpan CeilingInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Ceiling, true); + } + #endregion + + #region ConvertChecked + /// + /// Copies to a new converting each + /// value to a value. + /// + /// The input . + public static TensorSpan ConvertChecked(TensorSpan source) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase + { + return TensorPrimitivesHelperTFromSpanInTToSpanOut(source, TensorPrimitives.ConvertChecked); + } + #endregion + + #region ConvertSaturating + /// + /// Copies to a new converting each + /// value to a value. + /// + /// The input . + public static TensorSpan ConvertSaturating(TensorSpan source) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase + { + return TensorPrimitivesHelperTFromSpanInTToSpanOut(source, TensorPrimitives.ConvertSaturating); + } + #endregion + + #region ConvertTruncating + /// + /// Copies to a new converting each + /// value to a value. + /// + /// The input . + public static TensorSpan ConvertTruncating(TensorSpan source) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase + { + return TensorPrimitivesHelperTFromSpanInTToSpanOut(source, TensorPrimitives.ConvertTruncating); + } + #endregion + + #region CopySign + /// + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors and returns a new tensor with the result. + /// + /// Input . + /// The number with the associated sign. + public static TensorSpan CopySign(TensorSpan input, T sign) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTInSpanOut(input, sign, TensorPrimitives.CopySign); + } + + /// + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors in place. + /// + /// Input . + /// The number with the associated sign. + public static TensorSpan CopySignInPlace(TensorSpan input, T sign) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTInSpanOut(input, sign, TensorPrimitives.CopySign, true); + } + + /// + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors and returns a new with the result. + /// + /// Input . + /// The with the associated signs. + public static TensorSpan CopySign(TensorSpan input, TensorSpan sign) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperTwoSpanInSpanOut(input, sign, TensorPrimitives.CopySign); + } + + /// + /// Computes the element-wise result of copying the sign from one number to another number in the specified tensors in place. + /// + /// Input . + /// The with the associated signs. + public static TensorSpan CopySignInPlace(TensorSpan input, TensorSpan sign) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperTwoSpanInSpanOut(input, sign, TensorPrimitives.CopySign, true); + } + #endregion + + #region Cos + /// + /// Takes the cosine of each element of the and returns a new with the result. /// /// The to take the cosine of. public static TensorSpan Cos(TensorSpan input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cos); + } + + /// + /// Takes the cosine of each element of the in place. + /// + /// The to take the cosine of. + public static TensorSpan CosInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cos, true); + } + #endregion + + #region Cosh + /// + /// Takes the hyperbolic cosine of each element of the and returns a new with the result. + /// + /// The to take the cosine of. + public static TensorSpan Cosh(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cosh); + } + + /// + /// Takes the hyperbolic cosine of each element of the in place. + /// + /// The to take the cosine of. + public static TensorSpan CoshInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Cosh, true); + } + #endregion + + #region CosineSimilarity + /// + /// Compute cosine similarity between and . + /// + /// The first + /// The second + public static TensorSpan CosineSimilarity(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + if (left.Rank != 2) + ThrowHelper.ThrowArgument_2DTensorRequired(nameof(left)); + + if (right.Rank != 2) + ThrowHelper.ThrowArgument_2DTensorRequired(nameof(right)); + + if (left.Lengths[1] != right.Lengths[1]) + ThrowHelper.ThrowArgument_IncompatibleDimensions(left.Lengths[1], right.Lengths[1]); + + nint dim1 = left.Lengths[0]; + nint dim2 = right.Lengths[0]; + + T[] values = new T[dim1 * dim2]; + + scoped Span leftIndexes = stackalloc nint[2]; + scoped Span rightIndexes = stackalloc nint[2]; + + int outputOffset = 0; + + ReadOnlySpan lspan; + ReadOnlySpan rspan; + int rowLength = (int)left.Lengths[1]; + for (int i = 0; i < dim1; i++) + { + for (int j = 0; j < dim2; j++) + { + lspan = MemoryMarshal.CreateSpan(ref left[leftIndexes], rowLength); + rspan = MemoryMarshal.CreateSpan(ref right[rightIndexes], rowLength); + values[outputOffset++] = TensorPrimitives.CosineSimilarity(lspan, rspan); + rightIndexes[0]++; + } + rightIndexes[0] = 0; + leftIndexes[0]++; + } + + return new TensorSpan(values, 0, [dim1, dim2], []); + + } + #endregion + + #region CosPi + /// Computes the element-wise cosine of the value in the specified tensor that has been multiplied by Pi and returns a new with the results. + /// The input + /// + /// + /// This method effectively computes .CosPi([i]). + /// + /// + /// The angles in x must be in radians. Use or multiply by .Pi/180 to convert degrees to radians. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// + public static TensorSpan CosPi(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.CosPi); + } + + /// Computes the element-wise cosine of the value in the specified tensor that has been multiplied by Pi in place. + /// The input + /// + /// + /// This method effectively computes .CosPi([i]). + /// + /// + /// The angles in x must be in radians. Use or multiply by .Pi/180 to convert degrees to radians. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// + public static TensorSpan CosPiInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.CosPi, true); + } + #endregion + + #region DegreesToRadians + /// + /// Computes the element-wise conversion of each number of degrees in the specified tensor to radians and returns a new tensor with the results. + /// + /// The input . + public static TensorSpan DegreesToRadians(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.DegreesToRadians); + } + + /// + /// Computes the element-wise conversion of each number of degrees in the specified tensor to radians in place. + /// + /// The input . + public static TensorSpan DegreesToRadiansInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.DegreesToRadians, true); + } + #endregion + + #region Distance + /// + /// Computes the distance between two points, specified as non-empty, equal-length tensors of numbers, in Euclidean space. + /// + /// The input . + /// The input . + public static T Distance(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperTwoSpanInTOut(left, right, TensorPrimitives.Distance); + } + + #endregion + + #region Divide + /// + /// Divides each element of by and returns a new with the result. + /// + /// Input . + /// The divisor + public static TensorSpan Divide(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(span, val, ospan); + return output; + } + + /// + /// Divides each element of by in place. + /// + /// Input . + /// The divisor + public static TensorSpan DivideInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(span, val, ospan); + return output; + } + + /// + /// Divides by each element of and returns a new with the result."/> + /// + /// The value to be divided. + /// The divisor. + public static TensorSpan Divide(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(val, span, ospan); + return output; + } + + /// + /// Divides by each element of in place. + /// + /// The value to be divided. + /// The divisor. + public static TensorSpan DivideInPlace(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Divide(val, span, ospan); + return output; + } + + /// + /// Divides each element of by its corresponding element in and returns + /// a new with the result. + /// + /// The to be divided. + /// The divisor. + public static TensorSpan Divide(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Divide); + } + + /// + /// Divides each element of by its corresponding element in in place. + /// + /// The to be divided. + /// The divisor. + public static TensorSpan DivideInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IDivisionOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Divide, true); + } + #endregion + + #region Dot + /// + /// Computes the dot product of two tensors containing numbers. + /// + /// The input . + /// The input . + public static T Dot(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity, IMultiplicativeIdentity, IMultiplyOperators + { + return TensorPrimitivesHelperTwoSpanInTOut(left, right, TensorPrimitives.Dot); + } + + #endregion + + #region Exp + /// + /// Computes the element-wise result of raising e to the single-precision floating-point number powers in the specified tensor. + /// + /// The input . + public static TensorSpan Exp(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp); + } + + /// + /// Computes the element-wise result of raising e to the single-precision floating-point number powers in the specified tensor. + /// + /// The input . + public static TensorSpan ExpInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp, true); + } + #endregion + + #region Exp10 + /// + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor. + /// + /// The input . + public static TensorSpan Exp10(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10); + } + + /// + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor. + /// + /// The input . + public static TensorSpan Exp10InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10, true); + } + #endregion + + #region Exp10M1 + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor, minus one. + /// The input . + public static TensorSpan Exp10M1(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10M1); + } + + /// Computes the element-wise result of raising 10 to the number powers in the specified tensor, minus one. + /// The input . + public static TensorSpan Exp10M1InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp10M1, true); + } + #endregion + + #region Exp2 + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor. + /// The input . + public static TensorSpan Exp2(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2); + } + + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor. + /// The input . + public static TensorSpan Exp2InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2, true); + } + #endregion + + #region Exp2M1 + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor, minus one. + /// The input . + public static TensorSpan Exp2M1(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2M1); + } + + /// Computes the element-wise result of raising 2 to the number powers in the specified tensor, minus one. + /// The input . + public static TensorSpan Exp2M1InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Exp2M1, true); + } + #endregion + + #region ExpM1 + /// Computes the element-wise result of raising e to the number powers in the specified tensor, minus 1. + /// The input . + public static TensorSpan ExpM1(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.ExpM1); + } + + /// Computes the element-wise result of raising e to the number powers in the specified tensor, minus 1. + /// The input . + public static TensorSpan ExpM1InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.ExpM1, true); + } + #endregion + + #region Floor + /// Computes the element-wise floor of numbers in the specified tensor. + /// The input . + public static TensorSpan Floor(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Floor); + } + + /// Computes the element-wise floor of numbers in the specified tensor. + /// The input . + public static TensorSpan FloorInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Floor, true); + } + #endregion + + #region Hypotenuse + /// + /// Computes the element-wise hypotenuse given values from two tensors representing the lengths of the shorter sides in a right-angled triangle. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left . + /// Right . + public static TensorSpan Hypotenuse(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Hypot); + } + + /// + /// Computes the element-wise hypotenuse given values from two tensors representing the lengths of the shorter sides in a right-angled triangle. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left . + /// Right . + public static TensorSpan HypotenuseInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Hypot, true); + } + #endregion + + #region Ieee754Remainder + /// Computes the element-wise remainder of the numbers in the specified tensors. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// Left . + /// Right . + public static TensorSpan Ieee754Remainder(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Ieee754Remainder); + } + + /// + /// Computes the element-wise remainder of the numbers in the specified tensors. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left . + /// Right . + public static TensorSpan Ieee754RemainderInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Ieee754Remainder, true); + } + #endregion + + #region ILogB + /// Computes the element-wise floor of numbers in the specified tensor. + /// The input . + public static TensorSpan ILogB(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPointIeee754 + { + return TensorPrimitivesHelperSpanInIntSpanOut(input, TensorPrimitives.ILogB); + } + #endregion + + #region IndexOfMax + /// Searches for the index of the largest number in the specified tensor. + /// The input . + public static int IndexOfMax(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + return TensorPrimitives.IndexOfMax(span); + } + #endregion + + #region IndexOfMaxMagnitude + /// Searches for the index of the number with the largest magnitude in the specified tensor. + /// The input . + public static int IndexOfMaxMagnitude(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + return TensorPrimitives.IndexOfMaxMagnitude(span); + } + #endregion + + #region IndexOfMin + /// Searches for the index of the smallest number in the specified tensor. + /// The input . + public static int IndexOfMin(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + return TensorPrimitives.IndexOfMin(span); + } + #endregion + + #region IndexOfMinMagnitude + /// + /// Searches for the index of the number with the smallest magnitude in the specified tensor. + /// + /// The input . + public static int IndexOfMinMagnitude(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + return TensorPrimitives.IndexOfMinMagnitude(span); + } + #endregion + + #region LeadingZeroCount + /// + /// Computes the element-wise leading zero count of numbers in the specified tensor. + /// + /// The input . + public static TensorSpan LeadingZeroCount(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LeadingZeroCount); + } + + /// + /// Computes the element-wise leading zero count of numbers in the specified tensor. + /// + /// The input . + public static TensorSpan LeadingZeroCountInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LeadingZeroCount, true); + } + #endregion + + #region Log + + /// + /// Takes the natural logarithm of each element of the and returns a new with the result. + /// + /// The to take the natural logarithm of. + public static TensorSpan Log(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log); + } + + /// + /// Takes the natural logarithm of each element of the in place. + /// + /// The to take the natural logarithm of. + public static TensorSpan LogInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log, true); + } + #endregion + + #region Log10 + + /// + /// Takes the base 10 logarithm of each element of the and returns a new with the result. + /// + /// The to take the base 10 logarithm of. + public static TensorSpan Log10(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10); + } + + /// + /// Takes the base 10 logarithm of each element of the in place. + /// + /// The to take the base 10 logarithm of. + public static TensorSpan Log10InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10, true); + } + #endregion + + #region Log10P1 + /// + /// Takes the base 10 logarithm plus 1 of each element of the and returns a new with the result. + /// + /// The to take the base 10 logarithm of. + public static TensorSpan Log10P1(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10P1); + } + + /// + /// Takes the base 10 logarithm plus 1 of each element of the in place. + /// + /// The to take the base 10 logarithm of. + public static TensorSpan Log10P1InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log10P1, true); + } + #endregion + + #region Log2 + /// + /// Takes the base 2 logarithm of each element of the and returns a new with the result. + /// + /// The to take the base 2 logarithm of. + public static TensorSpan Log2(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2); + } + + /// + /// Takes the base 2 logarithm of each element of the in place. + /// + /// The to take the base 2 logarithm of. + public static TensorSpan Log2InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2, true); + } + #endregion + + #region Log2P1 + /// + /// Takes the base 2 logarithm plus 1 of each element of the and returns a new with the result. + /// + /// The to take the base 2 logarithm of. + public static TensorSpan Log2P1(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2P1); + } + + /// + /// Takes the base 2 logarithm plus 1 of each element of the in place. + /// + /// The to take the base 2 logarithm of. + public static TensorSpan Log2P1InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Log2P1, true); + } + #endregion + + #region LogP1 + /// + /// Takes the natural logarithm plus 1 of each element of the and returns a new with the result. + /// + /// The to take the natural logarithm of. + public static TensorSpan LogP1(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LogP1); + } + + /// + /// Takes the natural logarithm plus 1 of each element of the in place. + /// + /// The to take the natural logarithm of. + public static TensorSpan LogP1InPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.LogP1, true); + } + #endregion + + #region Max + /// Searches for the largest number in the specified tensor. + /// The input .. + public static T Max(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.Max); + } + #endregion + + #region MaxMagnitude + /// Searches for the number with the largest magnitude in the specified tensor. + /// The input .. + public static T MaxMagnitude(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MaxMagnitude); + } + #endregion + + #region MaxNumber + /// Searches for the largest number in the specified tensor. + /// The input .. + public static T MaxNumber(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MaxNumber); + } + #endregion + + #region Min + /// Searches for the smallest number in the specified tensor. + /// The input . + public static T Min(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.Min); + } + #endregion + + #region MinMagnitude + /// Searches for the number with the smallest magnitude in the specified tensor. + /// The input . + public static T MinMagnitude(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MinMagnitude); + } + #endregion + + #region MinNumber + /// Searches for the smallest number in the specified tensor. + /// The input .. + public static T MinNumber(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.MinNumber); + } + #endregion + + #region Multiply + /// + /// Multiplies each element of with and returns a new with the result. + /// + /// Input + /// value to multiply by. + public static TensorSpan Multiply(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Multiply(span, val, ospan); + return output; + } + + /// + /// Multiplies each element of with in place. + /// + /// Input + /// value to multiply by. + public static TensorSpan MultiplyInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Multiply(span, val, ospan); + return output; + } + + /// + /// Multiplies each element of with and returns a new with the result. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left for multiplication. + /// Right for multiplication. + public static TensorSpan Multiply(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Multiply); + } + + /// + /// Multiplies each element of with in place. + /// If the shapes are not the same they are broadcast to the smallest compatible shape. + /// + /// Left for multiplication. + /// Right for multiplication. + public static TensorSpan MultiplyInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IMultiplyOperators, IMultiplicativeIdentity + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Multiply, true); + } + #endregion + + #region Negate + /// Computes the element-wise negation of each number in the specified tensor. + /// The + public static TensorSpan Negate(TensorSpan input) + where T : IEquatable, IEqualityOperators, IUnaryNegationOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Negate); + } + + /// Computes the element-wise negation of each number in the specified tensor. + /// The + public static TensorSpan NegatePlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IUnaryNegationOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Negate, true); + } + #endregion + + #region Norm + + /// + /// Takes the norm of the and returns the result. + /// + /// The to take the norm of. + public static T Norm(TensorSpan input) + where T : IEquatable, IEqualityOperators, IRootFunctions + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + return TensorPrimitives.Norm(span); + } + #endregion + + #region OnesComplement + /// Computes the element-wise one's complement of numbers in the specified tensor. + /// The + public static TensorSpan OnesComplement(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.OnesComplement); + } + + /// Computes the element-wise one's complement of numbers in the specified tensor. + /// The + public static TensorSpan OnesComplementPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.OnesComplement, true); + } + #endregion + + #region PopCount + /// Computes the element-wise population count of numbers in the specified tensor. + /// The + public static TensorSpan PopCount(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.PopCount); + } + + /// Computes the element-wise population count of numbers in the specified tensor. + /// The + public static TensorSpan PopCountPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.PopCount, true); + } + #endregion + + #region Pow + /// Computes the element-wise power of a number in a specified tensor raised to a number in another specified tensors. + /// The input . + /// The second input + public static TensorSpan Pow(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IPowerFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Pow); + } + + /// Computes the element-wise power of a number in a specified tensor raised to a number in another specified tensors. + /// The input . + /// The second input + public static TensorSpan PowInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IPowerFunctions + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Pow, true); + } + #endregion + + #region Product + /// Computes the product of all elements in the specified non-empty tensor of numbers. + /// The input . + public static T Product(TensorSpan input) + where T : IEquatable, IEqualityOperators, IMultiplicativeIdentity, IMultiplyOperators + { + return TensorPrimitivesHelperSpanInTOut(input, TensorPrimitives.Product); + } + #endregion + + #region RadiansToDegrees + /// Computes the element-wise conversion of each number of radians in the specified tensor to degrees. + /// The input . + public static TensorSpan RadiansToDegrees(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.RadiansToDegrees); } - /// - /// Takes the cosine of each element of the in place. - /// - /// The to take the cosine of. - public static TensorSpan CosInPlace(TensorSpan input) + /// Computes the element-wise conversion of each number of radians in the specified tensor to degrees. + /// The input . + public static TensorSpan RadiansToDegreesInPlace(TensorSpan input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Cos, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.RadiansToDegrees, true); + } + #endregion + + #region Reciprocal + /// Computes the element-wise reciprocal of numbers in the specified tensor. + /// The input . + public static TensorSpan Reciprocal(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Reciprocal); + } + + /// Computes the element-wise reciprocal of numbers in the specified tensor. + /// The input . + public static TensorSpan ReciprocalInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Reciprocal, true); + } + #endregion + + #region Round + /// Computes the element-wise rounding of the numbers in the specified tensor + /// The input . + public static TensorSpan Round(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Round); + } + + /// Computes the element-wise rounding of the numbers in the specified tensor + /// The input . + public static TensorSpan RoundInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Round, true); + } + #endregion + + #region Sigmoid + /// Computes the element-wise sigmoid function on the specified non-empty tensor of numbers. + /// The input . + public static TensorSpan Sigmoid(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sigmoid); + } + + /// Computes the element-wise sigmoid function on the specified non-empty tensor of numbers. + /// The input . + public static TensorSpan SigmoidInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sigmoid, true); } #endregion @@ -577,7 +1736,7 @@ public static TensorSpan CosInPlace(TensorSpan input) public static TensorSpan Sin(TensorSpan input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sin); } /// @@ -587,7 +1746,61 @@ public static TensorSpan Sin(TensorSpan input) public static TensorSpan SinInPlace(TensorSpan input) where T : IEquatable, IEqualityOperators, ITrigonometricFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sin, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sin, true); + } + #endregion + + #region Sinh + /// Computes the element-wise hyperbolic sine of each radian angle in the specified tensor. + /// The to take the sin of. + public static TensorSpan Sinh(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sinh); + } + + /// Computes the element-wise hyperbolic sine of each radian angle in the specified tensor. + /// The to take the sin of. + public static TensorSpan SinhInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sinh, true); + } + #endregion + + #region SinPi + /// Computes the element-wise sine of the value in the specified tensor that has been multiplied by Pi. + /// The to take the sin of. + public static TensorSpan SinPi(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SinPi); + } + + /// Computes the element-wise sine of the value in the specified tensor that has been multiplied by Pi. + /// The to take the sin of. + public static TensorSpan SinPiInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SinPi, true); + } + #endregion + + #region SoftMax + /// Computes the softmax function over the specified non-empty tensor of numbers. + /// The to take the sin of. + public static TensorSpan SoftMax(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SoftMax); + } + + /// Computes the softmax function over the specified non-empty tensor of numbers. + /// The to take the sin of. + public static TensorSpan SoftMaxInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IExponentialFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.SoftMax, true); } #endregion @@ -599,7 +1812,7 @@ public static TensorSpan SinInPlace(TensorSpan input) public static TensorSpan Sqrt(TensorSpan input) where T : IEquatable, IEqualityOperators, IRootFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sqrt); } /// @@ -609,108 +1822,323 @@ public static TensorSpan Sqrt(TensorSpan input) public static TensorSpan SqrtInPlace(TensorSpan input) where T : IEquatable, IEqualityOperators, IRootFunctions { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Sqrt, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Sqrt, true); } #endregion - #region Log - + #region Subtract /// - /// Takes the natural logarithm of each element of the and returns a new with the result. + /// Subtracts from each element of and returns a new with the result. /// - /// The to take the natural logarithm of. - public static TensorSpan Log(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The with values to be subtracted from. + /// The value to subtract. + public static TensorSpan Subtract(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(span, val, ospan); + return output; } /// - /// Takes the natural logarithm of each element of the in place. + /// Subtracts from each element of in place. /// - /// The to take the natural logarithm of. - public static TensorSpan LogInPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The with values to be subtracted from. + /// The value to subtract. + public static TensorSpan SubtractInPlace(TensorSpan input, T val) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log, true); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(span, val, ospan); + return output; } - #endregion - #region Log10 + /// + /// Subtracts each element of from and returns a new with the result. + /// + /// The value to be subtracted from. + /// The values to subtract. + public static TensorSpan Subtract(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, ISubtractionOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + T[] values = new T[input.FlattenedLength]; + TensorSpan output = new TensorSpan(values, 0, input.Lengths, default); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(val, span, ospan); + return output; + } /// - /// Takes the base 10 logarithm of each element of the and returns a new with the result. + /// Subtracts each element of from in place. /// - /// The to take the base 10 logarithm of. - public static TensorSpan Log10(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The value to be subtracted from. + /// The values to subtract. + public static TensorSpan SubtractInPlace(T val, TensorSpan input) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = input; + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + TensorPrimitives.Subtract(val, span, ospan); + return output; } /// - /// Takes the base 10 logarithm of each element of the in place. + /// Subtracts each element of from and returns a new with the result. /// - /// The to take the base 10 logarithm of. - public static TensorSpan Log10InPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The of values to be subtracted from. + /// The of values to subtract. + public static TensorSpan Subtract(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log10, true); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Subtract); } - #endregion - #region Log2 /// - /// Takes the base 2 logarithm of each element of the and returns a new with the result. + /// Subtracts each element of from in place. /// - /// The to take the base 2 logarithm of. - public static TensorSpan Log2(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The of values to be subtracted from. + /// The of values to subtract. + public static TensorSpan SubtractInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, ISubtractionOperators { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2); + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Subtract, true); } + #endregion + #region Sum /// - /// Takes the base 2 logarithm of each element of the in place. + /// Sums all the elements of the and returns the result. /// - /// The to take the base 2 logarithm of. - public static TensorSpan Log2InPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ILogarithmicFunctions + /// The to sum. + public static T Sum(TensorSpan input) + where T : IEquatable, IEqualityOperators, IAdditionOperators, IAdditiveIdentity + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + return TensorPrimitives.Sum(span); + } + #endregion + + #region Tan + /// Computes the element-wise tangent of the value in the specified tensor. + /// The to take the sin of. + public static TensorSpan Tan(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tan); + } + + /// Computes the element-wise tangent of the value in the specified tensor. + /// The to take the sin of. + public static TensorSpan TanInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tan, true); + } + #endregion + + #region Tanh + /// Computes the element-wise hyperbolic tangent of each radian angle in the specified tensor. + /// The to take the sin of. + public static TensorSpan Tanh(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tanh); + } + + /// Computes the element-wise hyperbolic tangent of each radian angle in the specified tensor. + /// The to take the sin of. + public static TensorSpan TanhInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IHyperbolicFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Tanh, true); + } + #endregion + + #region TanPi + /// Computes the element-wise tangent of the value in the specified tensor that has been multiplied by Pi. + /// The to take the sin of. + public static TensorSpan TanPi(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TanPi); + } + + /// Computes the element-wise tangent of the value in the specified tensor that has been multiplied by Pi. + /// The to take the sin of. + public static TensorSpan TanPiInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TanPi, true); + } + #endregion + + #region TrailingZeroCount + /// Computes the element-wise trailing zero count of numbers in the specified tensor. + /// The input . + public static TensorSpan TrailingZeroCount(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TrailingZeroCount); + } + + /// Computes the element-wise trailing zero count of numbers in the specified tensor. + /// The input . + public static TensorSpan TrailingZeroCountInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IBinaryInteger + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.TrailingZeroCount, true); + } + #endregion + + #region Truncate + /// Computes the element-wise truncation of numbers in the specified tensor. + /// The input . + public static TensorSpan Truncate(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + { + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Truncate); + } + + /// Computes the element-wise truncation of numbers in the specified tensor. + /// The input . + public static TensorSpan TruncateInPlace(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint { - return TensorPrimitivesHelperT1(input, TensorPrimitives.Log2, true); + return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Truncate, true); + } + #endregion + + #region Xor + /// Computes the element-wise XOR of numbers in the specified tensors. + /// The left . + /// The right . + public static TensorSpan Xor(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Xor); + } + + /// Computes the element-wise XOR of numbers in the specified tensors. + /// The left . + /// The right . + public static TensorSpan XorInPlace(TensorSpan left, TensorSpan right) + where T : IEquatable, IEqualityOperators, IBitwiseOperators + { + return TensorPrimitivesHelperTwoSpanInSpanOut(left, right, TensorPrimitives.Xor, true); } #endregion #region TensorPrimitivesHelpers - private delegate void PerformCalculationT1(ReadOnlySpan input, Span output) + private delegate void PerformCalculationSpanInSpanOut(ReadOnlySpan input, Span output) + where T : IEquatable, IEqualityOperators; + + private delegate void PerformCalculationSpanInTInSpanOut(ReadOnlySpan input, T value, Span output) + where T : IEquatable, IEqualityOperators; + + private delegate void PerformCalculationTwoSpanInSpanOut(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output) + where T : IEquatable, IEqualityOperators; + + private delegate void PerformCalculationTFromSpanInTToSpanOut(ReadOnlySpan input, Span output) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase; + + private delegate T PerformCalculationTwoSpanInTOut(ReadOnlySpan input, ReadOnlySpan inputTwo) + where T : IEquatable, IEqualityOperators; + + private delegate void PerformCalculationSpanInIntSpanOut(ReadOnlySpan input, Span output) where T : IEquatable, IEqualityOperators; - private delegate void PerformCalculationT1T2(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output) + private delegate T PerformCalculationSpanInTOut(ReadOnlySpan input) where T : IEquatable, IEqualityOperators; - private static TensorSpan TensorPrimitivesHelperT1(TensorSpan input, PerformCalculationT1 performCalculation, bool inPlace = false) + private static T TensorPrimitivesHelperSpanInTOut(TensorSpan input, PerformCalculationSpanInTOut performCalculation) + where T : IEquatable, IEqualityOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + return performCalculation(span); + } + + private static TensorSpan TensorPrimitivesHelperSpanInIntSpanOut(TensorSpan input, PerformCalculationSpanInIntSpanOut performCalculation) + where T : IEquatable, IEqualityOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + int[] data = new int[input.FlattenedLength]; + performCalculation(span, data); + return new TensorSpan(data, 0, input.Lengths, input.Strides); + } + + private static T TensorPrimitivesHelperTwoSpanInTOut(TensorSpan left, TensorSpan right, PerformCalculationTwoSpanInTOut performCalculation) + where T : IEquatable, IEqualityOperators + { + // If not in place but sizes are the same. + if (left.Lengths.SequenceEqual(right.Lengths)) + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref left._reference, (int)left.FlattenedLength); + ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); + return performCalculation(span, rspan); + } + // Not in place and broadcasting needs to happen. + else + { + // Have a couple different possible cases here. + // 1 - Both tensors have row contiguous memory (i.e. a 1x5 being broadcast to a 5x5) + // 2 - One tensor has row contiguous memory and the right has column contiguous memory (i.e. a 1x5 and a 5x1) + // Because we are returning a single T though we need to actual realize the broadcasts at this point to perform the calculations. + + var broadcastedLeft = Broadcast(left, right); + var broadcastedRight = Broadcast(right, left); + + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref broadcastedLeft._reference, (int)broadcastedLeft.FlattenedLength); + ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref broadcastedRight._reference, (int)broadcastedRight.FlattenedLength); + return performCalculation(span, rspan); + } + } + + private static TensorSpan TensorPrimitivesHelperSpanInSpanOut(TensorSpan input, PerformCalculationSpanInSpanOut performCalculation, bool inPlace = false) + where T : IEquatable, IEqualityOperators + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + TensorSpan output = inPlace ? input : new TensorSpan(new T[input.FlattenedLength], 0, input.Lengths, input.Strides); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + performCalculation(span, ospan); + return output; + } + + private static TensorSpan TensorPrimitivesHelperSpanInTInSpanOut(TensorSpan input, T value, PerformCalculationSpanInTInSpanOut performCalculation, bool inPlace = false) where T : IEquatable, IEqualityOperators { ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); TensorSpan output = inPlace ? input : new TensorSpan(new T[input.FlattenedLength], 0, input.Lengths, input.Strides); Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + performCalculation(span, value, ospan); + return output; + } + + private static TensorSpan TensorPrimitivesHelperTFromSpanInTToSpanOut(TensorSpan input, PerformCalculationTFromSpanInTToSpanOut performCalculation) + where TFrom : IEquatable, IEqualityOperators, INumberBase + where TTo : INumberBase + { + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + TTo[] data = new TTo[(int)input.FlattenedLength]; + TensorSpan output = new TensorSpan(data, 0, input.Lengths, input.Strides); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output._flattenedLength); performCalculation(span, ospan); return output; } - private static TensorSpan TensorPrimitivesHelperT1T2(TensorSpan left, TensorSpan right, PerformCalculationT1T2 performCalculation, bool inPlace = false) + private static TensorSpan TensorPrimitivesHelperTwoSpanInSpanOut(TensorSpan left, TensorSpan right, PerformCalculationTwoSpanInSpanOut performCalculation, bool inPlace = false) where T : IEquatable, IEqualityOperators { if (inPlace && left.Lengths != right.Lengths) ThrowHelper.ThrowArgument_InPlaceInvalidShape(); - //ReadOnlySpan span = MemoryMarshal.CreateSpan(ref tensor._reference, (int)tensor.FlattenedLength); - //ReadOnlySpan rspan = MemoryMarshal.CreateSpan(ref right._reference, (int)right.FlattenedLength); - //TensorSpan output = inPlace ? tensor : Create(tensor.IsPinned, tensor.Lengths); - //Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - //performCalculation(span, rspan, ospan); - //return output; - TensorSpan output; if (inPlace) { From 46ba380a160b2e1f7d7922f136cc12d4ce4f5ea1 Mon Sep 17 00:00:00 2001 From: Michael Sharp Date: Mon, 3 Jun 2024 13:29:39 -0600 Subject: [PATCH 3/5] ref updates --- .../ref/System.Numerics.Tensors.netcore.cs | 446 ++++++++++++++---- .../src/System.Numerics.Tensors.csproj | 2 +- .../Tensors/netcore/TensorExtensions.cs | 28 +- .../Tensors/netcore/TensorSpanExtensions.cs | 165 ++++++- .../Tensors/netcore/TensorSpanHelpers.cs | 5 + 5 files changed, 528 insertions(+), 118 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs index 0b6241008f6fe..cae21b2950473 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs @@ -55,41 +55,41 @@ namespace System.Buffers } namespace System.Numerics.Tensors { - public partial interface IReadOnlyTensor : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable where TSelf : System.Numerics.Tensors.IReadOnlyTensor + public partial interface IReadOnlyTensor : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable where TSelf : System.Numerics.Tensors.IReadOnlyTensor { static abstract TSelf? Empty { get; } nint FlattenedLength { get; } bool IsEmpty { get; } bool IsPinned { get; } - T this[scoped System.ReadOnlySpan indexes] { get; } - TSelf this[scoped System.ReadOnlySpan ranges] { get; } - T this[scoped System.ReadOnlySpan indexes] { get; } + T this[params scoped System.ReadOnlySpan indexes] { get; } + TSelf this[params scoped System.ReadOnlySpan ranges] { get; } + T this[params scoped System.ReadOnlySpan indexes] { get; } int Rank { get; } System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(); - System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(scoped System.ReadOnlySpan startIndex); - System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(scoped System.ReadOnlySpan range); - System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(scoped System.ReadOnlySpan start); + System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan startIndex); + System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan range); + System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan start); void CopyTo(scoped System.Numerics.Tensors.TensorSpan destination); void FlattenTo(scoped System.Span destination); void GetLengths(scoped System.Span destination); ref readonly T GetPinnableReference(); void GetStrides(scoped System.Span destination); - TSelf Slice(scoped System.ReadOnlySpan startIndex); - TSelf Slice(scoped System.ReadOnlySpan range); - TSelf Slice(scoped System.ReadOnlySpan start); + TSelf Slice(params scoped System.ReadOnlySpan startIndex); + TSelf Slice(params scoped System.ReadOnlySpan range); + TSelf Slice(params scoped System.ReadOnlySpan start); bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan destination); bool TryFlattenTo(scoped System.Span destination); } public partial interface ITensor : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor where TSelf : System.Numerics.Tensors.ITensor { bool IsReadOnly { get; } - new T this[scoped System.ReadOnlySpan indexes] { get; set; } - new TSelf this[scoped System.ReadOnlySpan ranges] { get; set; } - new T this[scoped System.ReadOnlySpan indexes] { get; set; } + new T this[params scoped System.ReadOnlySpan indexes] { get; set; } + new TSelf this[params scoped System.ReadOnlySpan ranges] { get; set; } + new T this[params scoped System.ReadOnlySpan indexes] { get; set; } System.Numerics.Tensors.TensorSpan AsTensorSpan(); - System.Numerics.Tensors.TensorSpan AsTensorSpan(scoped System.ReadOnlySpan startIndex); - System.Numerics.Tensors.TensorSpan AsTensorSpan(scoped System.ReadOnlySpan range); - System.Numerics.Tensors.TensorSpan AsTensorSpan(scoped System.ReadOnlySpan start); + System.Numerics.Tensors.TensorSpan AsTensorSpan(params scoped System.ReadOnlySpan startIndex); + System.Numerics.Tensors.TensorSpan AsTensorSpan(params scoped System.ReadOnlySpan range); + System.Numerics.Tensors.TensorSpan AsTensorSpan(params scoped System.ReadOnlySpan start); void Clear(); static abstract TSelf Create(scoped System.ReadOnlySpan lengths, bool pinned = false); static abstract TSelf Create(scoped System.ReadOnlySpan lengths, scoped System.ReadOnlySpan strides, bool pinned = false); @@ -117,9 +117,9 @@ public readonly ref partial struct ReadOnlyTensorSpan public static System.Numerics.Tensors.ReadOnlyTensorSpan Empty { get { throw null; } } public nint FlattenedLength { get { throw null; } } public bool IsEmpty { get { throw null; } } - public ref readonly T this[scoped System.ReadOnlySpan indexes] { get { throw null; } } - public System.Numerics.Tensors.ReadOnlyTensorSpan this[scoped System.ReadOnlySpan ranges] { get { throw null; } } - public ref readonly T this[scoped System.ReadOnlySpan indexes] { get { throw null; } } + public ref readonly T this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } + public System.Numerics.Tensors.ReadOnlyTensorSpan this[params scoped System.ReadOnlySpan ranges] { get { throw null; } } + public ref readonly T this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] public System.ReadOnlySpan Lengths { get { throw null; } } public int Rank { get { throw null; } } @@ -143,8 +143,8 @@ public void CopyTo(scoped System.Numerics.Tensors.TensorSpan destination) { } public static bool operator ==(System.Numerics.Tensors.ReadOnlyTensorSpan left, System.Numerics.Tensors.ReadOnlyTensorSpan right) { throw null; } public static implicit operator System.Numerics.Tensors.ReadOnlyTensorSpan (T[]? array) { throw null; } public static bool operator !=(System.Numerics.Tensors.ReadOnlyTensorSpan left, System.Numerics.Tensors.ReadOnlyTensorSpan right) { throw null; } - public System.Numerics.Tensors.ReadOnlyTensorSpan Slice(scoped System.ReadOnlySpan indexes) { throw null; } - public System.Numerics.Tensors.ReadOnlyTensorSpan Slice(scoped System.ReadOnlySpan ranges) { throw null; } + public System.Numerics.Tensors.ReadOnlyTensorSpan Slice(params scoped System.ReadOnlySpan indexes) { throw null; } + public System.Numerics.Tensors.ReadOnlyTensorSpan Slice(params scoped System.ReadOnlySpan ranges) { throw null; } public override string ToString() { throw null; } public bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan destination) { throw null; } public bool TryFlattenTo(scoped System.Span destination) { throw null; } @@ -159,115 +159,198 @@ public ref partial struct Enumerator } public static partial class Tensor { - public static System.Numerics.Tensors.TensorSpan AddInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } - public static System.Numerics.Tensors.TensorSpan AddInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } + public static System.Numerics.Tensors.Tensor AbsInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Abs(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AcoshInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Acosh(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AcosInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AcosPiInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AcosPi(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Acos(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } public static System.Numerics.Tensors.Tensor AddInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } public static System.Numerics.Tensors.Tensor AddInPlace(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } - public static System.Numerics.Tensors.TensorSpan Add(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } - public static System.Numerics.Tensors.TensorSpan Add(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } public static System.Numerics.Tensors.Tensor Add(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } public static System.Numerics.Tensors.Tensor Add(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } - public static System.Numerics.Tensors.Tensor Broadcast(System.Numerics.Tensors.Tensor input, scoped System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor AsinhInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Asinh(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AsinInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AsinPiInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AsinPi(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Asin(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Atan2InPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.Tensor Atan2PiInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.Tensor Atan2Pi(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.Tensor Atan2(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.Tensor AtanhInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Atanh(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AtanInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AtanPiInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AtanPi(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Atan(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor BitwiseAndInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor BitwiseAnd(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor BitwiseOrInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor BitwiseOr(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor Broadcast(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor Broadcast(System.Numerics.Tensors.Tensor input, System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor CeilingInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor Ceiling(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.Tensor Concatenate(System.ReadOnlySpan> tensors, int axis = 0) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan CosInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor ConvertChecked(System.Numerics.Tensors.Tensor source) where TFrom : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase where TTo : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.Tensor ConvertSaturating(System.Numerics.Tensors.Tensor source) where TFrom : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase where TTo : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.Tensor ConvertTruncating(System.Numerics.Tensors.Tensor source) where TFrom : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase where TTo : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.Tensor CopySignInPlace(System.Numerics.Tensors.Tensor input, System.Numerics.Tensors.Tensor sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.Tensor CopySignInPlace(System.Numerics.Tensors.Tensor input, T sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.Tensor CopySign(System.Numerics.Tensors.Tensor input, System.Numerics.Tensors.Tensor sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.Tensor CopySign(System.Numerics.Tensors.Tensor input, T sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.Tensor CoshInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Cosh(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor CosineSimilarity(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } public static System.Numerics.Tensors.Tensor CosInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Cos(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor CosPiInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor CosPi(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } public static System.Numerics.Tensors.Tensor Cos(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } - public static System.Numerics.Tensors.Tensor CreateAndFillGaussianNormalDistribution(scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } - public static System.Numerics.Tensors.Tensor CreateAndFillUniformDistribution(scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor CreateAndFillGaussianNormalDistribution(params scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor CreateAndFillUniformDistribution(params scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.Tensor CreateFromEnumerable(System.Collections.Generic.IEnumerable data) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.Tensor CreateUninitialized(scoped System.ReadOnlySpan lengths, bool pinned = false) where T : System.IEquatable { throw null; } public static System.Numerics.Tensors.Tensor CreateUninitialized(scoped System.ReadOnlySpan lengths, scoped System.ReadOnlySpan strides, bool pinned = false) where T : System.IEquatable { throw null; } public static System.Numerics.Tensors.Tensor Create(scoped System.ReadOnlySpan lengths, bool pinned = false) where T : System.IEquatable { throw null; } public static System.Numerics.Tensors.Tensor Create(scoped System.ReadOnlySpan lengths, scoped System.ReadOnlySpan strides, bool pinned = false) where T : System.IEquatable { throw null; } public static System.Numerics.Tensors.Tensor Create(T[] values, scoped System.ReadOnlySpan lengths) where T : System.IEquatable { throw null; } - public static System.Numerics.Tensors.Tensor Create(T[] values, scoped System.ReadOnlySpan lengths, scoped System.ReadOnlySpan strides) where T : System.IEquatable { throw null; } - public static System.Numerics.Tensors.TensorSpan DivideInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan DivideInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static System.Numerics.Tensors.Tensor Create(T[] values, scoped System.ReadOnlySpan lengths, scoped System.ReadOnlySpan strides, bool isPinned = false) where T : System.IEquatable { throw null; } + public static System.Numerics.Tensors.Tensor CubeRootInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.Tensor CubeRoot(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.Tensor DegreesToRadiansInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor DegreesToRadians(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static T Distance(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } public static System.Numerics.Tensors.Tensor DivideInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } public static System.Numerics.Tensors.Tensor DivideInPlace(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan DivideInPlace(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } public static System.Numerics.Tensors.Tensor DivideInPlace(T val, System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Divide(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Divide(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } public static System.Numerics.Tensors.Tensor Divide(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } public static System.Numerics.Tensors.Tensor Divide(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Divide(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } public static System.Numerics.Tensors.Tensor Divide(T val, System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static T Dot(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators { throw null; } + public static System.Numerics.Tensors.Tensor Exp10InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp10M1InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp10M1(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp10(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp2InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp2M1InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp2M1(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp2(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor ExpInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor ExpM1InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor ExpM1(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Exp(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } public static System.Numerics.Tensors.Tensor FilteredUpdate(System.Numerics.Tensors.Tensor tensor, System.Numerics.Tensors.Tensor filter, System.Numerics.Tensors.Tensor values) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.Tensor FilteredUpdate(System.Numerics.Tensors.Tensor tensor, System.Numerics.Tensors.Tensor filter, T value) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor FloorInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor Floor(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static bool GreaterThanAll(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } public static bool GreaterThanAny(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } public static System.Numerics.Tensors.Tensor GreaterThan(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } public static System.Numerics.Tensors.Tensor GreaterThan(System.Numerics.Tensors.Tensor left, T right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } + public static System.Numerics.Tensors.Tensor HypotenuseInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Hypotenuse(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Ieee754RemainderInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.Tensor Ieee754Remainder(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.Tensor ILogB(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static int IndexOfMaxMagnitude(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static int IndexOfMax(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static int IndexOfMinMagnitude(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static int IndexOfMin(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.Tensor LeadingZeroCountInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.Tensor LeadingZeroCount(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } public static bool LessThanAll(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } public static bool LessThanAny(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } public static System.Numerics.Tensors.Tensor LessThan(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } public static System.Numerics.Tensors.Tensor LessThan(System.Numerics.Tensors.Tensor left, T right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IComparisonOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Log10InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } public static System.Numerics.Tensors.Tensor Log10InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Log10(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Log10P1InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Log10P1(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } public static System.Numerics.Tensors.Tensor Log10(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Log2InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } public static System.Numerics.Tensors.Tensor Log2InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Log2(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Log2P1InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Log2P1(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } public static System.Numerics.Tensors.Tensor Log2(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan LogInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } public static System.Numerics.Tensors.Tensor LogInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Log(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor LogP1InPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor LogP1(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } public static System.Numerics.Tensors.Tensor Log(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static T MaxMagnitude(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T MaxNumber(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T Max(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } public static T Mean(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static TResult Mean(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber where TResult : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } - public static System.Numerics.Tensors.TensorSpan MultiplyInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } - public static System.Numerics.Tensors.TensorSpan MultiplyInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } + public static T MinMagnitude(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T MinNumber(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T Min(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } public static System.Numerics.Tensors.Tensor MultiplyInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } public static System.Numerics.Tensors.Tensor MultiplyInPlace(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } - public static System.Numerics.Tensors.TensorSpan Multiply(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } - public static System.Numerics.Tensors.TensorSpan Multiply(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } public static System.Numerics.Tensors.Tensor Multiply(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } public static System.Numerics.Tensors.Tensor Multiply(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } - public static T Norm(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.Tensor NegatePlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } + public static System.Numerics.Tensors.Tensor Negate(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } public static T Norm(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } - public static System.Numerics.Tensors.Tensor Permute(System.Numerics.Tensors.Tensor input, scoped System.ReadOnlySpan axis) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Reshape(this System.Numerics.Tensors.TensorSpan input, scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.Tensor Reshape(this System.Numerics.Tensors.Tensor input, scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Resize(System.Numerics.Tensors.TensorSpan input, scoped System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.Tensor Resize(System.Numerics.Tensors.Tensor input, scoped System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Reverse(System.Numerics.Tensors.TensorSpan input, nint axis = -1) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor OnesComplementPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor OnesComplement(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor Permute(System.Numerics.Tensors.Tensor input, params scoped System.ReadOnlySpan axis) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor PopCountPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.Tensor PopCount(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.Tensor PowInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Pow(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } + public static T Product(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators { throw null; } + public static System.Numerics.Tensors.Tensor RadiansToDegreesInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor RadiansToDegrees(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor ReciprocalInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor Reciprocal(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor Reshape(this System.Numerics.Tensors.Tensor input, params scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Resize(System.Numerics.Tensors.TensorSpan input, System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor Resize(System.Numerics.Tensors.Tensor input, System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.Tensor Reverse(System.Numerics.Tensors.Tensor input, nint axis = -1) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor RoundInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor Round(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.Tensor SequenceEqual(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.Tensor SetSlice(this System.Numerics.Tensors.Tensor tensor, System.Numerics.Tensors.Tensor values, scoped System.ReadOnlySpan ranges) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan SinInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor SetSlice(this System.Numerics.Tensors.Tensor tensor, System.Numerics.Tensors.Tensor values, params scoped System.ReadOnlySpan ranges) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor SigmoidInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Sigmoid(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor SinhInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Sinh(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } public static System.Numerics.Tensors.Tensor SinInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Sin(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor SinPiInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor SinPi(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } public static System.Numerics.Tensors.Tensor Sin(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor SoftMaxInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.Tensor SoftMax(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } public static System.Numerics.Tensors.Tensor[] Split(System.Numerics.Tensors.Tensor input, nint numSplits, nint axis) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan SqrtInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } public static System.Numerics.Tensors.Tensor SqrtInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Sqrt(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } public static System.Numerics.Tensors.Tensor Sqrt(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } public static System.Numerics.Tensors.Tensor Squeeze(System.Numerics.Tensors.Tensor input, int axis = -1) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.Tensor Stack(System.Numerics.Tensors.Tensor[] input, int axis = 0) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static T StdDev(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint, System.Numerics.IPowerFunctions, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } - public static TResult StdDev(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber where TResult : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } - public static System.Numerics.Tensors.TensorSpan SubtractInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan SubtractInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } + public static TResult StdDev(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber, System.Numerics.IFloatingPoint, System.Numerics.IPowerFunctions, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity where TResult : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.Tensor SubtractInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } public static System.Numerics.Tensors.Tensor SubtractInPlace(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan SubtractInPlace(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } public static System.Numerics.Tensors.Tensor SubtractInPlace(T val, System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Subtract(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Subtract(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } public static System.Numerics.Tensors.Tensor Subtract(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } public static System.Numerics.Tensors.Tensor Subtract(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Subtract(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } public static System.Numerics.Tensors.Tensor Subtract(T val, System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } - public static T Sum(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } public static T Sum(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } - public static string ToString(this System.Numerics.Tensors.ReadOnlyTensorSpan span, scoped System.ReadOnlySpan maximumLengths) { throw null; } - public static string ToString(this System.Numerics.Tensors.TensorSpan span, scoped System.ReadOnlySpan maximumLengths) { throw null; } + public static System.Numerics.Tensors.Tensor TanhInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Tanh(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.Tensor TanInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor TanPiInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor TanPi(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor Tan(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor TrailingZeroCountInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.Tensor TrailingZeroCount(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } public static System.Numerics.Tensors.Tensor Transpose(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor TruncateInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.Tensor Truncate(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.Tensor Unsqueeze(System.Numerics.Tensors.Tensor input, int axis) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.Tensor XorInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor Xor(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } } public static partial class TensorPrimitives { @@ -422,8 +505,174 @@ public static void Xor(System.ReadOnlySpan x, T y, System.Span destinat } public static partial class TensorSpan { - public static System.Numerics.Tensors.TensorSpan AsTensorSpan(this T[]? array, scoped System.ReadOnlySpan shape) { throw null; } + public static System.Numerics.Tensors.TensorSpan AbsInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Abs(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AcoshInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Acosh(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AcosInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AcosPiInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AcosPi(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Acos(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AddInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan AddInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan Add(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan Add(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan AsinhInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Asinh(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AsinInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AsinPiInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AsinPi(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Asin(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AsTensorSpan(this T[]? array, params scoped System.ReadOnlySpan shape) { throw null; } + public static System.Numerics.Tensors.TensorSpan Atan2InPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.TensorSpan Atan2PiInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.TensorSpan Atan2Pi(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.TensorSpan Atan2(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.TensorSpan AtanhInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Atanh(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AtanInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AtanPiInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AtanPi(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Atan(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan BitwiseAndInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan BitwiseAnd(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan BitwiseOrInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan BitwiseOr(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Broadcast(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Broadcast(System.Numerics.Tensors.TensorSpan input, System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan CeilingInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan Ceiling(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan ConvertChecked(System.Numerics.Tensors.TensorSpan source) where TFrom : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase where TTo : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.TensorSpan ConvertSaturating(System.Numerics.Tensors.TensorSpan source) where TFrom : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase where TTo : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.TensorSpan ConvertTruncating(System.Numerics.Tensors.TensorSpan source) where TFrom : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase where TTo : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.TensorSpan CopySignInPlace(System.Numerics.Tensors.TensorSpan input, System.Numerics.Tensors.TensorSpan sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.TensorSpan CopySignInPlace(System.Numerics.Tensors.TensorSpan input, T sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.TensorSpan CopySign(System.Numerics.Tensors.TensorSpan input, System.Numerics.Tensors.TensorSpan sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.TensorSpan CopySign(System.Numerics.Tensors.TensorSpan input, T sign) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.TensorSpan CoshInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Cosh(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan CosineSimilarity(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan CosInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan CosPiInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan CosPi(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Cos(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan CubeRootInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan CubeRoot(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan DegreesToRadiansInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan DegreesToRadians(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static T Distance(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan DivideInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan DivideInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan DivideInPlace(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Divide(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Divide(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Divide(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IDivisionOperators { throw null; } + public static T Dot(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp10InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp10M1InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp10M1(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp10(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp2InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp2M1InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp2M1(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp2(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan ExpInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan ExpM1InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan ExpM1(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Exp(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan FloorInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan Floor(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan HypotenuseInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Hypotenuse(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Ieee754RemainderInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.TensorSpan Ieee754Remainder(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static System.Numerics.Tensors.TensorSpan ILogB(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointIeee754 { throw null; } + public static int IndexOfMaxMagnitude(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static int IndexOfMax(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static int IndexOfMinMagnitude(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static int IndexOfMin(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.TensorSpan LeadingZeroCountInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.TensorSpan LeadingZeroCount(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.TensorSpan Log10InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log10P1InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log10P1(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log10(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log2InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log2P1InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log2P1(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log2(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan LogInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan LogP1InPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan LogP1(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Log(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ILogarithmicFunctions { throw null; } + public static T MaxMagnitude(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T MaxNumber(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T Max(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T Mean(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static TResult Mean(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber where TResult : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static T MinMagnitude(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T MinNumber(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static T Min(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber { throw null; } + public static System.Numerics.Tensors.TensorSpan MultiplyInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan MultiplyInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan Multiply(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan Multiply(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan NegatePlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Negate(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } + public static T Norm(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan OnesComplementPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan OnesComplement(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan PopCountPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.TensorSpan PopCount(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.TensorSpan PowInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Pow(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } + public static T Product(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan RadiansToDegreesInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan RadiansToDegrees(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan ReciprocalInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan Reciprocal(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan Reshape(this System.Numerics.Tensors.TensorSpan input, params scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Reverse(System.Numerics.Tensors.TensorSpan input, nint axis = -1) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan RoundInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan Round(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static bool SequenceEqual(this System.Numerics.Tensors.TensorSpan span, System.Numerics.Tensors.TensorSpan other) where T : System.IEquatable? { throw null; } + public static System.Numerics.Tensors.TensorSpan SigmoidInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Sigmoid(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan SinhInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Sinh(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan SinInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan SinPiInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan SinPi(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Sin(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan SoftMaxInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan SoftMax(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan SqrtInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Sqrt(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Squeeze(System.Numerics.Tensors.TensorSpan input, int axis = -1) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static T StdDev(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint, System.Numerics.IPowerFunctions, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } + public static TResult StdDev(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumber, System.Numerics.IFloatingPoint, System.Numerics.IPowerFunctions, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity where TResult : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan SubtractInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan SubtractInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan SubtractInPlace(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Subtract(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Subtract(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Subtract(T val, System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ISubtractionOperators { throw null; } + public static T Sum(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity { throw null; } + public static System.Numerics.Tensors.TensorSpan TanhInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Tanh(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan TanInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan TanPiInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan TanPi(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan Tan(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static string ToString(this System.Numerics.Tensors.ReadOnlyTensorSpan span, params scoped System.ReadOnlySpan maximumLengths) { throw null; } + public static string ToString(this System.Numerics.Tensors.TensorSpan span, params scoped System.ReadOnlySpan maximumLengths) { throw null; } + public static System.Numerics.Tensors.TensorSpan TrailingZeroCountInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.TensorSpan TrailingZeroCount(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.TensorSpan TruncateInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan Truncate(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } + public static System.Numerics.Tensors.TensorSpan Unsqueeze(System.Numerics.Tensors.TensorSpan input, int axis) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan XorInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Xor(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } } public readonly ref partial struct TensorSpan { @@ -444,9 +693,9 @@ public readonly ref partial struct TensorSpan public static System.Numerics.Tensors.TensorSpan Empty { get { throw null; } } public nint FlattenedLength { get { throw null; } } public bool IsEmpty { get { throw null; } } - public ref T this[scoped System.ReadOnlySpan indexes] { get { throw null; } } - public System.Numerics.Tensors.TensorSpan this[scoped System.ReadOnlySpan ranges] { get { throw null; } set { } } - public ref T this[scoped System.ReadOnlySpan indexes] { get { throw null; } } + public ref T this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } + public System.Numerics.Tensors.TensorSpan this[params scoped System.ReadOnlySpan ranges] { get { throw null; } set { } } + public ref T this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] public System.ReadOnlySpan Lengths { get { throw null; } } public int Rank { get { throw null; } } @@ -456,7 +705,7 @@ public void Clear() { } public void CopyTo(scoped System.Numerics.Tensors.TensorSpan destination) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("Equals() on TensorSpan will always throw an exception. Use the equality operator instead.")] -#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member + #pragma warning disable CS0809 // Obsolete member overrides non-obsolete member public override bool Equals(object? obj) { throw null; } #pragma warning restore CS0809 // Obsolete member overrides non-obsolete member public void Fill(T value) { } @@ -473,8 +722,8 @@ public void FlattenTo(scoped System.Span destination) { } public static implicit operator System.Numerics.Tensors.ReadOnlyTensorSpan (System.Numerics.Tensors.TensorSpan span) { throw null; } public static implicit operator System.Numerics.Tensors.TensorSpan (T[]? array) { throw null; } public static bool operator !=(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) { throw null; } - public System.Numerics.Tensors.TensorSpan Slice(scoped System.ReadOnlySpan indexes) { throw null; } - public System.Numerics.Tensors.TensorSpan Slice(scoped System.ReadOnlySpan ranges) { throw null; } + public System.Numerics.Tensors.TensorSpan Slice(params scoped System.ReadOnlySpan indexes) { throw null; } + public System.Numerics.Tensors.TensorSpan Slice(params scoped System.ReadOnlySpan ranges) { throw null; } public override string ToString() { throw null; } public bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan destination) { throw null; } public bool TryFlattenTo(scoped System.Span destination) { throw null; } @@ -494,26 +743,26 @@ internal Tensor() { } public bool IsEmpty { get { throw null; } } public bool IsPinned { get { throw null; } } public System.Numerics.Tensors.Tensor this[System.Numerics.Tensors.Tensor filter] { get { throw null; } } - public ref T this[scoped System.ReadOnlySpan indexes] { get { throw null; } } - public System.Numerics.Tensors.Tensor this[scoped System.ReadOnlySpan ranges] { get { throw null; } set { } } - public ref T this[scoped System.ReadOnlySpan indexes] { get { throw null; } } + public ref T this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } + public System.Numerics.Tensors.Tensor this[params scoped System.ReadOnlySpan ranges] { get { throw null; } set { } } + public ref T this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } public System.ReadOnlySpan Lengths { get { throw null; } } public int Rank { get { throw null; } } public System.ReadOnlySpan Strides { get { throw null; } } - T System.Numerics.Tensors.IReadOnlyTensor, T>.this[scoped System.ReadOnlySpan indexes] { get { throw null; } } - System.Numerics.Tensors.Tensor System.Numerics.Tensors.IReadOnlyTensor, T>.this[scoped System.ReadOnlySpan ranges] { get { throw null; } } - T System.Numerics.Tensors.IReadOnlyTensor, T>.this[scoped System.ReadOnlySpan indexes] { get { throw null; } } + T System.Numerics.Tensors.IReadOnlyTensor, T>.this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } + System.Numerics.Tensors.Tensor System.Numerics.Tensors.IReadOnlyTensor, T>.this[params scoped System.ReadOnlySpan ranges] { get { throw null; } } + T System.Numerics.Tensors.IReadOnlyTensor, T>.this[params scoped System.ReadOnlySpan indexes] { get { throw null; } } bool System.Numerics.Tensors.ITensor, T>.IsReadOnly { get { throw null; } } - T System.Numerics.Tensors.ITensor, T>.this[scoped System.ReadOnlySpan indexes] { get { throw null; } set { } } - T System.Numerics.Tensors.ITensor, T>.this[scoped System.ReadOnlySpan indexes] { get { throw null; } set { } } + T System.Numerics.Tensors.ITensor, T>.this[params scoped System.ReadOnlySpan indexes] { get { throw null; } set { } } + T System.Numerics.Tensors.ITensor, T>.this[params scoped System.ReadOnlySpan indexes] { get { throw null; } set { } } public System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan() { throw null; } - public System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(scoped System.ReadOnlySpan startIndex) { throw null; } - public System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(scoped System.ReadOnlySpan start) { throw null; } - public System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(scoped System.ReadOnlySpan start) { throw null; } + public System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan startIndex) { throw null; } + public System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan start) { throw null; } + public System.Numerics.Tensors.ReadOnlyTensorSpan AsReadOnlyTensorSpan(params scoped System.ReadOnlySpan start) { throw null; } public System.Numerics.Tensors.TensorSpan AsTensorSpan() { throw null; } - public System.Numerics.Tensors.TensorSpan AsTensorSpan(scoped System.ReadOnlySpan startIndex) { throw null; } - public System.Numerics.Tensors.TensorSpan AsTensorSpan(scoped System.ReadOnlySpan start) { throw null; } - public System.Numerics.Tensors.TensorSpan AsTensorSpan(scoped System.ReadOnlySpan start) { throw null; } + public System.Numerics.Tensors.TensorSpan AsTensorSpan(params scoped System.ReadOnlySpan startIndex) { throw null; } + public System.Numerics.Tensors.TensorSpan AsTensorSpan(params scoped System.ReadOnlySpan start) { throw null; } + public System.Numerics.Tensors.TensorSpan AsTensorSpan(params scoped System.ReadOnlySpan start) { throw null; } public void Clear() { } public void CopyTo(System.Numerics.Tensors.TensorSpan destination) { } public void Fill(T value) { } @@ -524,20 +773,21 @@ public void FlattenTo(System.Span destination) { } public ref T GetPinnableReference() { throw null; } public static implicit operator System.Numerics.Tensors.ReadOnlyTensorSpan (System.Numerics.Tensors.Tensor value) { throw null; } public static implicit operator System.Numerics.Tensors.TensorSpan (System.Numerics.Tensors.Tensor value) { throw null; } - public System.Numerics.Tensors.Tensor Slice(scoped System.ReadOnlySpan startIndex) { throw null; } - public System.Numerics.Tensors.Tensor Slice(scoped System.ReadOnlySpan start) { throw null; } - public System.Numerics.Tensors.Tensor Slice(scoped System.ReadOnlySpan start) { throw null; } + public static implicit operator System.Numerics.Tensors.Tensor (T[] array) { throw null; } + public System.Numerics.Tensors.Tensor Slice(params scoped System.ReadOnlySpan startIndex) { throw null; } + public System.Numerics.Tensors.Tensor Slice(params scoped System.ReadOnlySpan start) { throw null; } + public System.Numerics.Tensors.Tensor Slice(params scoped System.ReadOnlySpan start) { throw null; } System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } void System.Numerics.Tensors.IReadOnlyTensor, T>.GetLengths(System.Span destination) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] ref readonly T System.Numerics.Tensors.IReadOnlyTensor, T>.GetPinnableReference() { throw null; } void System.Numerics.Tensors.IReadOnlyTensor, T>.GetStrides(scoped System.Span destination) { } - static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.Create(scoped System.ReadOnlySpan lengths, bool pinned) { throw null; } - static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.Create(scoped System.ReadOnlySpan lengths, scoped System.ReadOnlySpan strides, bool pinned) { throw null; } - static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.CreateUninitialized(scoped System.ReadOnlySpan lengths, bool pinned) { throw null; } - static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.CreateUninitialized(scoped System.ReadOnlySpan lengths, scoped System.ReadOnlySpan strides, bool pinned) { throw null; } - public string ToString(scoped System.ReadOnlySpan maximumLengths) { throw null; } + static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.Create(System.ReadOnlySpan lengths, bool pinned) { throw null; } + static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.Create(System.ReadOnlySpan lengths, System.ReadOnlySpan strides, bool pinned) { throw null; } + static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.CreateUninitialized(System.ReadOnlySpan lengths, bool pinned) { throw null; } + static System.Numerics.Tensors.Tensor System.Numerics.Tensors.ITensor, T>.CreateUninitialized(System.ReadOnlySpan lengths, System.ReadOnlySpan strides, bool pinned) { throw null; } + public string ToString(params scoped System.ReadOnlySpan maximumLengths) { throw null; } public bool TryCopyTo(System.Numerics.Tensors.TensorSpan destination) { throw null; } public bool TryFlattenTo(System.Span destination) { throw null; } } diff --git a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj index cfa810e067548..0044dbdd1a4cf 100644 --- a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj @@ -6,7 +6,7 @@ true Provides support for operating over tensors. ReferenceAssemblyExclusions.txt - false + true diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs index ca9901492f7ff..778474cecfa16 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs @@ -25,7 +25,7 @@ public static partial class Tensor /// /// Input . /// of the desired new shape. - public static Tensor Resize(Tensor input, scoped ReadOnlySpan shape) + public static Tensor Resize(Tensor input, ReadOnlySpan shape) where T : IEquatable, IEqualityOperators { nint newSize = TensorSpanHelpers.CalculateTotalLength(shape); @@ -46,7 +46,7 @@ public static Tensor Resize(Tensor input, scoped ReadOnlySpan sha /// /// Input . /// of the desired new shape. - public static TensorSpan Resize(TensorSpan input, scoped ReadOnlySpan shape) + public static TensorSpan Resize(TensorSpan input, ReadOnlySpan shape) where T : IEquatable, IEqualityOperators { nint newSize = TensorSpanHelpers.CalculateTotalLength(shape); @@ -85,7 +85,7 @@ public static Tensor Broadcast(Tensor left, Tensor right) /// Input . /// of the desired new shape. /// Thrown when the shapes are not broadcast compatible. - public static Tensor Broadcast(Tensor input, scoped ReadOnlySpan shape) + public static Tensor Broadcast(Tensor input, ReadOnlySpan shape) where T : IEquatable, IEqualityOperators { Tensor intermediate = BroadcastTo(input, shape); @@ -295,7 +295,7 @@ public static Tensor[] Split(Tensor input, nint numSplits, nint axis) /// Input . /// The values you want to set in the . /// The ranges you want to set. - public static Tensor SetSlice(this Tensor tensor, Tensor values, params scoped ReadOnlySpan ranges) + public static Tensor SetSlice(this Tensor tensor, Tensor values, params ReadOnlySpan ranges) where T : IEquatable, IEqualityOperators { TensorSpan srcSpan; @@ -845,7 +845,7 @@ public static Tensor Stack(Tensor[] input, int axis = 0) /// /// you want to reshape. /// with the new dimensions. - public static Tensor Reshape(this Tensor input, params scoped ReadOnlySpan lengths) + public static Tensor Reshape(this Tensor input, params ReadOnlySpan lengths) where T : IEquatable, IEqualityOperators { nint[] arrLengths = lengths.ToArray(); @@ -1081,12 +1081,18 @@ public static T StdDev(Tensor input) /// The to take the standard deviation of. /// representing the standard deviation. public static TResult StdDev(Tensor input) - where T : IEquatable, IEqualityOperators, INumber + where T : IEquatable, IEqualityOperators, INumber, IFloatingPoint, IPowerFunctions, IAdditionOperators, IAdditiveIdentity where TResult : IEquatable, IEqualityOperators, IFloatingPoint { - T sum = Tensor.Sum(input); - return TResult.CreateChecked(TResult.CreateChecked(sum) / TResult.CreateChecked(input.FlattenedLength)); + T mean = Mean(input); + Span span = MemoryMarshal.CreateSpan(ref input._values[0], (int)input._flattenedLength); + Span output = new T[input._flattenedLength].AsSpan(); + TensorPrimitives.Subtract(span, mean, output); + TensorPrimitives.Abs(output, output); + TensorPrimitives.Pow((ReadOnlySpan)output, T.CreateChecked(2), output); + T sum = TensorPrimitives.Sum((ReadOnlySpan)output); + return TResult.CreateChecked(sum / T.CreateChecked(input.FlattenedLength)); } #endregion @@ -1101,7 +1107,7 @@ public static T Mean(Tensor input) where T : IEquatable, IEqualityOperators, IFloatingPoint { - T sum = Tensor.Sum(input); + T sum = Sum(input); return T.CreateChecked(sum / T.CreateChecked(input.FlattenedLength)); } @@ -1115,7 +1121,7 @@ public static TResult Mean(Tensor input) where TResult : IEquatable, IEqualityOperators, IFloatingPoint { - T sum = Tensor.Sum(input); + T sum = Sum(input); return TResult.CreateChecked(TResult.CreateChecked(sum) / TResult.CreateChecked(input.FlattenedLength)); } @@ -1145,7 +1151,7 @@ public static Tensor Transpose(Tensor input) /// /// Input /// with the new axis ordering. - public static Tensor Permute(Tensor input, params scoped ReadOnlySpan axis) + public static Tensor Permute(Tensor input, params ReadOnlySpan axis) where T : IEquatable, IEqualityOperators { if (input.Rank == 1) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs index 5135dac23ee5c..c2aa5776693c7 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; +using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -11,14 +12,15 @@ namespace System.Numerics.Tensors { public static class TensorSpan { + #region SequenceEqual /// /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe bool SequenceEqual(this TensorSpan span, TensorSpan other) where T : IEquatable? => span.FlattenedLength == other.FlattenedLength && span.Lengths.SequenceEqual(other.Lengths) && TensorSpanHelpers.SequenceEqual(ref span.GetPinnableReference(), ref other.GetPinnableReference(), (nuint)span.FlattenedLength); + #endregion - // Doing a copy here for shape because otherwise I get a CS8347 about potentially exposing it beyond its lifetime. In this case that would never happen - // because we were always doing a copy of the shape in the constructor anyways, but I couldn't figure out another way around it. + #region AsTensorSpan /// /// Extension method to more easily create a TensorSpan from an array. /// @@ -26,7 +28,8 @@ public static class TensorSpan /// The with the data /// The shape for the /// - public static TensorSpan AsTensorSpan(this T[]? array, params scoped ReadOnlySpan shape) => new(array, 0, shape, default); + public static TensorSpan AsTensorSpan(this T[]? array, params ReadOnlySpan shape) => new(array, 0, shape, default); + #endregion #region ToString // REVIEW: WHAT SHOULD WE NAME THIS? WHERE DO WE WANT IT TO LIVE? @@ -36,7 +39,7 @@ public static class TensorSpan /// The you want to represent as a string. /// Maximum Length of each dimension /// A representation of the - public static string ToString(this TensorSpan span, params scoped ReadOnlySpan maximumLengths) => ((ReadOnlyTensorSpan)span).ToString(maximumLengths); + public static string ToString(this TensorSpan span, params ReadOnlySpan maximumLengths) => ((ReadOnlyTensorSpan)span).ToString(maximumLengths); /// /// Creates a representation of the ."/> @@ -44,7 +47,7 @@ public static class TensorSpan /// /// The you want to represent as a string. /// Maximum Length of each dimension - public static string ToString(this ReadOnlyTensorSpan span, params scoped ReadOnlySpan maximumLengths) + public static string ToString(this ReadOnlyTensorSpan span, params ReadOnlySpan maximumLengths) { var sb = new StringBuilder(); scoped Span curIndexes; @@ -106,7 +109,7 @@ public static TensorSpan Broadcast(TensorSpan left, TensorSpan right /// Input . /// of the desired new shape. /// Thrown when the shapes are not broadcast compatible. - public static TensorSpan Broadcast(TensorSpan input, scoped ReadOnlySpan shape) + public static TensorSpan Broadcast(TensorSpan input, ReadOnlySpan shape) where T : IEquatable, IEqualityOperators { TensorSpan intermediate = BroadcastTo(input, shape); @@ -124,7 +127,7 @@ public static TensorSpan Broadcast(TensorSpan input, scoped ReadOnlySpa /// Input . /// of the desired new shape. /// Thrown when the shapes are not broadcast compatible. - internal static TensorSpan BroadcastTo(TensorSpan input, scoped ReadOnlySpan shape) + internal static TensorSpan BroadcastTo(TensorSpan input, ReadOnlySpan shape) where T : IEquatable, IEqualityOperators { if (input.Lengths.SequenceEqual(shape)) @@ -243,7 +246,7 @@ public static TensorSpan Reverse(TensorSpan input, nint axis = -1) /// /// you want to reshape. /// with the new dimensions. - public static TensorSpan Reshape(this TensorSpan input, params scoped ReadOnlySpan lengths) + public static TensorSpan Reshape(this TensorSpan input, params ReadOnlySpan lengths) where T : IEquatable, IEqualityOperators { nint[] arrLengths = lengths.ToArray(); @@ -272,6 +275,152 @@ public static TensorSpan Reshape(this TensorSpan input, params scoped R } #endregion + #region Squeeze + // REVIEW: NAME? + /// + /// Removes axis of length one from the . defaults to -1 and will remove all axis with length of 1. + /// If is specified, it will only remove that axis and if it is not of length one it will throw an exception. + /// + /// The to remove axis of length 1. + /// The axis to remove. Defaults to -1 which removes all axis of length 1. + public static TensorSpan Squeeze(TensorSpan input, int axis = -1) + where T : IEquatable, IEqualityOperators + { + if (axis >= input.Rank) + ThrowHelper.ThrowArgument_AxisLargerThanRank(); + + nint[] lengths; + nint[] strides; + + List tempLengths = new List(); + if (axis == -1) + { + for (int i = 0; i < input.Lengths.Length; i++) + { + if (input.Lengths[i] != 1) + { + tempLengths.Add(input.Lengths[i]); + } + } + lengths = tempLengths.ToArray(); + strides = TensorSpanHelpers.CalculateStrides(lengths); + } + else + { + if (input.Lengths[axis] != 1) + { + ThrowHelper.ThrowArgument_InvalidSqueezeAxis(); + } + for (int i = 0; i < input.Lengths.Length; i++) + { + if (i != axis) + { + tempLengths.Add(input.Lengths[i]); + } + } + lengths = tempLengths.ToArray(); + strides = TensorSpanHelpers.CalculateStrides(lengths); + } + + return new TensorSpan(ref input._reference, lengths, strides, input._memoryLength); + } + #endregion + + #region Unsqueeze + // REVIEW: NAME? NUMPY CALLS THIS expand_dims. + /// + /// Insert a new axis of length 1 that will appear at the axis position. + /// + /// The to remove axis of length 1. + /// The axis to add. + public static TensorSpan Unsqueeze(TensorSpan input, int axis) + where T : IEquatable, IEqualityOperators + { + if (axis > input.Lengths.Length) + ThrowHelper.ThrowArgument_AxisLargerThanRank(); + if (axis < 0) + axis = input.Rank - axis; + + List tempLengths = input._lengths.ToArray().ToList(); + tempLengths.Insert(axis, 1); + nint[] lengths = tempLengths.ToArray(); + nint[] strides = TensorSpanHelpers.CalculateStrides(lengths); + return new TensorSpan(ref input._reference, lengths, strides, input._memoryLength); + } + #endregion + + #region StdDev + /// + /// Returns the standard deviation of the elements in the tensor. + /// + /// The to take the standard deviation of. + /// representing the standard deviation. + public static T StdDev(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint, IPowerFunctions, IAdditionOperators, IAdditiveIdentity + + { + T mean = Mean(input); + Span span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + Span output = new T[input._flattenedLength].AsSpan(); + TensorPrimitives.Subtract(span, mean, output); + TensorPrimitives.Abs(output, output); + TensorPrimitives.Pow((ReadOnlySpan)output, T.CreateChecked(2), output); + T sum = TensorPrimitives.Sum((ReadOnlySpan)output); + return T.CreateChecked(sum / T.CreateChecked(input.FlattenedLength)); + } + + /// + /// Return the standard deviation of the elements in the tensor. Casts the return value to . + /// + /// The to take the standard deviation of. + /// representing the standard deviation. + public static TResult StdDev(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber, IFloatingPoint, IPowerFunctions, IAdditionOperators, IAdditiveIdentity + where TResult : IEquatable, IEqualityOperators, IFloatingPoint + + { + T mean = Mean(input); + Span span = MemoryMarshal.CreateSpan(ref input._reference, (int)input._flattenedLength); + Span output = new T[input._flattenedLength].AsSpan(); + TensorPrimitives.Subtract(span, mean, output); + TensorPrimitives.Abs(output, output); + TensorPrimitives.Pow((ReadOnlySpan)output, T.CreateChecked(2), output); + T sum = TensorPrimitives.Sum((ReadOnlySpan)output); + return TResult.CreateChecked(sum / T.CreateChecked(input.FlattenedLength)); + } + + #endregion + + #region Mean + /// + /// Returns the mean of the elements in the tensor. + /// + /// The to take the mean of. + /// representing the mean. + public static T Mean(TensorSpan input) + where T : IEquatable, IEqualityOperators, IFloatingPoint + + { + T sum = Sum(input); + return T.CreateChecked(sum / T.CreateChecked(input.FlattenedLength)); + } + + /// + /// Return the mean of the elements in the tensor. Casts the return value to . + /// + /// The to take the mean of. + /// representing the mean. + public static TResult Mean(TensorSpan input) + where T : IEquatable, IEqualityOperators, INumber + where TResult : IEquatable, IEqualityOperators, IFloatingPoint + + { + T sum = Sum(input); + return TResult.CreateChecked(TResult.CreateChecked(sum) / TResult.CreateChecked(input.FlattenedLength)); + } + + #endregion + #region TensorPrimitives #region Abs /// diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs index ed6e91c67cd19..344226025c277 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Collections.Specialized; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -13,6 +14,10 @@ namespace System.Numerics.Tensors { internal static partial class TensorSpanHelpers { + + internal static bool AreShapesTheSame(ReadOnlyTensorSpan tensor1, ReadOnlyTensorSpan tensor2) + where T : IEquatable, IEqualityOperators => tensor1._lengths.SequenceEqual(tensor2._lengths); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static nint CalculateTotalLength(ReadOnlySpan lengths) { From 68ecee0cb5364ba6ae59261bc5fb3ef20124ef7f Mon Sep 17 00:00:00 2001 From: Michael Sharp Date: Tue, 4 Jun 2024 17:21:44 -0600 Subject: [PATCH 4/5] more testing --- .../ref/System.Numerics.Tensors.netcore.cs | 26 +- .../Tensors/netcore/TensorExtensions.cs | 32 +- .../Tensors/netcore/TensorSpanExtensions.cs | 58 +++- .../Tensors/netcore/TensorSpanHelpers.T.cs | 15 - .../System.Numerics.Tensors/tests/Helpers.cs | 1 + .../tests/TensorSpanTests.cs | 284 +++++++++++++++++- .../tests/TensorTests.cs | 280 ++++++++++++++++- 7 files changed, 627 insertions(+), 69 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs index cae21b2950473..bb7bd1d57d694 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs @@ -159,8 +159,8 @@ public ref partial struct Enumerator } public static partial class Tensor { - public static System.Numerics.Tensors.Tensor AbsInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } - public static System.Numerics.Tensors.Tensor Abs(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.Tensor AbsInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.Tensor Abs(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase { throw null; } public static System.Numerics.Tensors.Tensor AcoshInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } public static System.Numerics.Tensors.Tensor Acosh(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } public static System.Numerics.Tensors.Tensor AcosInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } @@ -290,13 +290,13 @@ public static partial class Tensor public static System.Numerics.Tensors.Tensor MultiplyInPlace(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } public static System.Numerics.Tensors.Tensor Multiply(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } public static System.Numerics.Tensors.Tensor Multiply(System.Numerics.Tensors.Tensor input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } - public static System.Numerics.Tensors.Tensor NegatePlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } + public static System.Numerics.Tensors.Tensor NegateInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } public static System.Numerics.Tensors.Tensor Negate(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } public static T Norm(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } - public static System.Numerics.Tensors.Tensor OnesComplementPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.Tensor OnesComplementInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } public static System.Numerics.Tensors.Tensor OnesComplement(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } public static System.Numerics.Tensors.Tensor Permute(System.Numerics.Tensors.Tensor input, params scoped System.ReadOnlySpan axis) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.Tensor PopCountPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.Tensor PopCountInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } public static System.Numerics.Tensors.Tensor PopCount(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } public static System.Numerics.Tensors.Tensor PowInPlace(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } public static System.Numerics.Tensors.Tensor Pow(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } @@ -306,7 +306,6 @@ public static partial class Tensor public static System.Numerics.Tensors.Tensor ReciprocalInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.Tensor Reciprocal(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.Tensor Reshape(this System.Numerics.Tensors.Tensor input, params scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan Resize(System.Numerics.Tensors.TensorSpan input, System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.Tensor Resize(System.Numerics.Tensors.Tensor input, System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.Tensor Reverse(System.Numerics.Tensors.Tensor input, nint axis = -1) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.Tensor RoundInPlace(System.Numerics.Tensors.Tensor input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } @@ -505,8 +504,8 @@ public static void Xor(System.ReadOnlySpan x, T y, System.Span destinat } public static partial class TensorSpan { - public static System.Numerics.Tensors.TensorSpan AbsInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan Abs(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } + public static System.Numerics.Tensors.TensorSpan AbsInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase { throw null; } + public static System.Numerics.Tensors.TensorSpan Abs(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.INumberBase { throw null; } public static System.Numerics.Tensors.TensorSpan AcoshInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } public static System.Numerics.Tensors.TensorSpan Acosh(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } public static System.Numerics.Tensors.TensorSpan AcosInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.ITrigonometricFunctions { throw null; } @@ -617,12 +616,12 @@ public static partial class TensorSpan public static System.Numerics.Tensors.TensorSpan MultiplyInPlace(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } public static System.Numerics.Tensors.TensorSpan Multiply(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } public static System.Numerics.Tensors.TensorSpan Multiply(System.Numerics.Tensors.TensorSpan input, T val) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IMultiplyOperators, System.Numerics.IMultiplicativeIdentity { throw null; } - public static System.Numerics.Tensors.TensorSpan NegatePlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan NegateInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } public static System.Numerics.Tensors.TensorSpan Negate(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IUnaryNegationOperators { throw null; } public static T Norm(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IRootFunctions { throw null; } - public static System.Numerics.Tensors.TensorSpan OnesComplementPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan OnesComplementInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } public static System.Numerics.Tensors.TensorSpan OnesComplement(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBitwiseOperators { throw null; } - public static System.Numerics.Tensors.TensorSpan PopCountPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } + public static System.Numerics.Tensors.TensorSpan PopCountInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } public static System.Numerics.Tensors.TensorSpan PopCount(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IBinaryInteger { throw null; } public static System.Numerics.Tensors.TensorSpan PowInPlace(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } public static System.Numerics.Tensors.TensorSpan Pow(System.Numerics.Tensors.TensorSpan left, System.Numerics.Tensors.TensorSpan right) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IPowerFunctions { throw null; } @@ -632,10 +631,13 @@ public static partial class TensorSpan public static System.Numerics.Tensors.TensorSpan ReciprocalInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.TensorSpan Reciprocal(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.TensorSpan Reshape(this System.Numerics.Tensors.TensorSpan input, params scoped System.ReadOnlySpan lengths) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } + public static System.Numerics.Tensors.TensorSpan Resize(System.Numerics.Tensors.TensorSpan input, System.ReadOnlySpan shape) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.TensorSpan Reverse(System.Numerics.Tensors.TensorSpan input, nint axis = -1) where T : System.IEquatable, System.Numerics.IEqualityOperators { throw null; } public static System.Numerics.Tensors.TensorSpan RoundInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } public static System.Numerics.Tensors.TensorSpan Round(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint { throw null; } - public static bool SequenceEqual(this System.Numerics.Tensors.TensorSpan span, System.Numerics.Tensors.TensorSpan other) where T : System.IEquatable? { throw null; } + public static bool SequenceEqual(this System.Numerics.Tensors.ReadOnlyTensorSpan span, in System.Numerics.Tensors.ReadOnlyTensorSpan other) where T : System.IEquatable? { throw null; } + public static bool SequenceEqual(this System.Numerics.Tensors.TensorSpan span, in System.Numerics.Tensors.ReadOnlyTensorSpan other) where T : System.IEquatable? { throw null; } + public static bool SequenceEqual(this System.Numerics.Tensors.TensorSpan span, in System.Numerics.Tensors.TensorSpan other) where T : System.IEquatable? { throw null; } public static System.Numerics.Tensors.TensorSpan SigmoidInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } public static System.Numerics.Tensors.TensorSpan Sigmoid(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions { throw null; } public static System.Numerics.Tensors.TensorSpan SinhInPlace(System.Numerics.Tensors.TensorSpan input) where T : System.IEquatable, System.Numerics.IEqualityOperators, System.Numerics.IHyperbolicFunctions { throw null; } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs index 778474cecfa16..4927b46eb658a 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorExtensions.cs @@ -41,26 +41,6 @@ public static Tensor Resize(Tensor input, ReadOnlySpan shape) return output; } - /// - /// Creates a new , allocates new managed memory, and copies the data from . If the final shape is smaller all data after - /// - /// Input . - /// of the desired new shape. - public static TensorSpan Resize(TensorSpan input, ReadOnlySpan shape) - where T : IEquatable, IEqualityOperators - { - nint newSize = TensorSpanHelpers.CalculateTotalLength(shape); - T[] values = new T[newSize]; - TensorSpan output = new TensorSpan(values, 0, shape, default); - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); - Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); - if (newSize > input.FlattenedLength) - TensorSpanHelpers.Memmove(ospan, span, input.FlattenedLength); - else - TensorSpanHelpers.Memmove(ospan, span, newSize); - - return output; - } #endregion #region Broadcast @@ -1229,7 +1209,7 @@ public static Tensor Permute(Tensor input, params ReadOnlySpan axi /// /// The to take the sin of. public static Tensor Abs(Tensor input) - where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + where T : IEquatable, IEqualityOperators, INumberBase { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs); } @@ -1239,7 +1219,7 @@ public static Tensor Abs(Tensor input) /// /// The to take the sin of. public static Tensor AbsInPlace(Tensor input) - where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + where T : IEquatable, IEqualityOperators, INumberBase { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs, true); } @@ -2520,7 +2500,7 @@ public static Tensor Negate(Tensor input) /// Computes the element-wise negation of each number in the specified tensor. /// The - public static Tensor NegatePlace(Tensor input) + public static Tensor NegateInPlace(Tensor input) where T : IEquatable, IEqualityOperators, IUnaryNegationOperators { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Negate, true); @@ -2550,7 +2530,7 @@ public static Tensor OnesComplement(Tensor input) /// Computes the element-wise one's complement of numbers in the specified tensor. /// The - public static Tensor OnesComplementPlace(Tensor input) + public static Tensor OnesComplementInPlace(Tensor input) where T : IEquatable, IEqualityOperators, IBitwiseOperators { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.OnesComplement, true); @@ -2568,7 +2548,7 @@ public static Tensor PopCount(Tensor input) /// Computes the element-wise population count of numbers in the specified tensor. /// The - public static Tensor PopCountPlace(Tensor input) + public static Tensor PopCountInPlace(Tensor input) where T : IEquatable, IEqualityOperators, IBinaryInteger { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.PopCount, true); @@ -3058,7 +3038,7 @@ private static Tensor TensorPrimitivesHelperTFromSpanInTToSpanOut TensorPrimitivesHelperTwoSpanInSpanOut(Tensor left, Tensor right, PerformCalculationTwoSpanInSpanOut performCalculation, bool inPlace = false) where T : IEquatable, IEqualityOperators { - if (inPlace && left.Lengths != right.Lengths) + if (inPlace && !left.Lengths.SequenceEqual(right.Lengths)) ThrowHelper.ThrowArgument_InPlaceInvalidShape(); Tensor output; diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs index c2aa5776693c7..65a0f697d9c04 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanExtensions.cs @@ -16,8 +16,27 @@ public static class TensorSpan /// /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T). /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe bool SequenceEqual(this TensorSpan span, TensorSpan other) where T : IEquatable? => span.FlattenedLength == other.FlattenedLength && span.Lengths.SequenceEqual(other.Lengths) && TensorSpanHelpers.SequenceEqual(ref span.GetPinnableReference(), ref other.GetPinnableReference(), (nuint)span.FlattenedLength); + public static bool SequenceEqual(this ReadOnlyTensorSpan span, in ReadOnlyTensorSpan other) where T : IEquatable? + { + return span.FlattenedLength == other.FlattenedLength + && MemoryMarshal.CreateReadOnlySpan(in span.GetPinnableReference(), (int)span.FlattenedLength).SequenceEqual(MemoryMarshal.CreateReadOnlySpan(in other.GetPinnableReference(), (int)other.FlattenedLength)); + } + + /// + /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T). + /// + public static bool SequenceEqual(this TensorSpan span, in TensorSpan other) where T : IEquatable? + { + return ((ReadOnlyTensorSpan)span).SequenceEqual((ReadOnlyTensorSpan)other); + } + + /// + /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T). + /// + public static bool SequenceEqual(this TensorSpan span, in ReadOnlyTensorSpan other) where T : IEquatable? + { + return ((ReadOnlyTensorSpan)span).SequenceEqual(other); + } #endregion #region AsTensorSpan @@ -275,6 +294,29 @@ public static TensorSpan Reshape(this TensorSpan input, params ReadOnly } #endregion + #region Resize + /// + /// Creates a new , allocates new managed memory, and copies the data from . If the final shape is smaller all data after + /// + /// Input . + /// of the desired new shape. + public static TensorSpan Resize(TensorSpan input, ReadOnlySpan shape) + where T : IEquatable, IEqualityOperators + { + nint newSize = TensorSpanHelpers.CalculateTotalLength(shape); + T[] values = new T[newSize]; + TensorSpan output = new TensorSpan(values, 0, shape, default); + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref input._reference, (int)input.FlattenedLength); + Span ospan = MemoryMarshal.CreateSpan(ref output._reference, (int)output.FlattenedLength); + if (newSize > input.FlattenedLength) + TensorSpanHelpers.Memmove(ospan, span, input.FlattenedLength); + else + TensorSpanHelpers.Memmove(ospan, span, newSize); + + return output; + } + #endregion + #region Squeeze // REVIEW: NAME? /// @@ -428,7 +470,7 @@ public static TResult Mean(TensorSpan input) /// /// The to take the sin of. public static TensorSpan Abs(TensorSpan input) - where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + where T : IEquatable, IEqualityOperators, INumberBase { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs); } @@ -438,7 +480,7 @@ public static TensorSpan Abs(TensorSpan input) /// /// The to take the sin of. public static TensorSpan AbsInPlace(TensorSpan input) - where T : IEquatable, IEqualityOperators, ITrigonometricFunctions + where T : IEquatable, IEqualityOperators, INumberBase { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Abs, true); } @@ -1717,7 +1759,7 @@ public static TensorSpan Negate(TensorSpan input) /// Computes the element-wise negation of each number in the specified tensor. /// The - public static TensorSpan NegatePlace(TensorSpan input) + public static TensorSpan NegateInPlace(TensorSpan input) where T : IEquatable, IEqualityOperators, IUnaryNegationOperators { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.Negate, true); @@ -1749,7 +1791,7 @@ public static TensorSpan OnesComplement(TensorSpan input) /// Computes the element-wise one's complement of numbers in the specified tensor. /// The - public static TensorSpan OnesComplementPlace(TensorSpan input) + public static TensorSpan OnesComplementInPlace(TensorSpan input) where T : IEquatable, IEqualityOperators, IBitwiseOperators { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.OnesComplement, true); @@ -1767,7 +1809,7 @@ public static TensorSpan PopCount(TensorSpan input) /// Computes the element-wise population count of numbers in the specified tensor. /// The - public static TensorSpan PopCountPlace(TensorSpan input) + public static TensorSpan PopCountInPlace(TensorSpan input) where T : IEquatable, IEqualityOperators, IBinaryInteger { return TensorPrimitivesHelperSpanInSpanOut(input, TensorPrimitives.PopCount, true); @@ -2285,7 +2327,7 @@ private static TensorSpan TensorPrimitivesHelperTFromSpanInTToSpanOut TensorPrimitivesHelperTwoSpanInSpanOut(TensorSpan left, TensorSpan right, PerformCalculationTwoSpanInSpanOut performCalculation, bool inPlace = false) where T : IEquatable, IEqualityOperators { - if (inPlace && left.Lengths != right.Lengths) + if (inPlace && !left.Lengths.SequenceEqual(right.Lengths)) ThrowHelper.ThrowArgument_InPlaceInvalidShape(); TensorSpan output; diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs index 2b2d62a58f9a5..4e5103a0acd6e 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpanHelpers.T.cs @@ -52,20 +52,5 @@ public static unsafe void Fill(ref T dest, nuint numElements, T value) numElements -= toFill; } } - - public static bool SequenceEqual(ref T first, ref T second, nuint length) where T : IEquatable? - { - bool equal = true; - while (length > 0) - { - nuint toCompare = Math.Min(length, int.MaxValue); - equal &= MemoryMarshal.CreateSpan(ref first, (int)toCompare).SequenceEqual(MemoryMarshal.CreateSpan(ref second, (int)toCompare)); - first = ref Unsafe.Add(ref first, toCompare); - second = ref Unsafe.Add(ref second, toCompare); - length -= toCompare; - } - - return equal; - } } } diff --git a/src/libraries/System.Numerics.Tensors/tests/Helpers.cs b/src/libraries/System.Numerics.Tensors/tests/Helpers.cs index 052d22d0e1837..d2e213e937264 100644 --- a/src/libraries/System.Numerics.Tensors/tests/Helpers.cs +++ b/src/libraries/System.Numerics.Tensors/tests/Helpers.cs @@ -14,6 +14,7 @@ public static class Helpers public static IEnumerable TensorLengthsIncluding0 => Enumerable.Range(0, 257); public static IEnumerable TensorLengths => Enumerable.Range(1, 256); + public static IEnumerable TensorShapes => [[1], [2], [10], [1,1], [1,2], [2,2], [5, 5], [2, 2, 2], [5, 5, 5], [3, 3, 3, 3], [4, 4, 4, 4, 4]]; // Tolerances taken from testing in the scalar math routines: // cf. https://github.com/dotnet/runtime/blob/89f7ad3b276fb0b48f20cb4e8408bdce85c2b415/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs index e09b1a988cb1f..3937cd4a94008 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs @@ -1,19 +1,295 @@ // 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.Reflection; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.InteropServices; using Xunit; namespace System.Numerics.Tensors.Tests { public class TensorSpanTests { + #region TensorPrimitivesForwardsTests + private void FillTensor(Span span) + where T : INumberBase + { + for (int i = 0; i < span.Length; i++) + { + span[i] = T.CreateChecked((Random.Shared.NextSingle() * 100) - 50); + } + } + + private static nint CalculateTotalLength(ReadOnlySpan lengths) + { + if (lengths.IsEmpty) + return 0; + nint totalLength = 1; + for (int i = 0; i < lengths.Length; i++) + { + totalLength *= lengths[i]; + } + + return totalLength; + } + + public delegate void TensorPrimitivesSpanInSpanOut(ReadOnlySpan input, Span output); + public delegate TensorSpan TensorSpanInSpanOut(TensorSpan input); + + public static IEnumerable SpanInSpanOutData() + { + yield return Create(TensorPrimitives.Abs, TensorSpan.Abs); + yield return Create(TensorPrimitives.Abs, TensorSpan.AbsInPlace); + yield return Create(TensorPrimitives.Acos, TensorSpan.Acos); + yield return Create(TensorPrimitives.Acos, TensorSpan.AcosInPlace); + yield return Create(TensorPrimitives.Acosh, TensorSpan.Acosh); + yield return Create(TensorPrimitives.Acosh, TensorSpan.AcoshInPlace); + yield return Create(TensorPrimitives.AcosPi, TensorSpan.AcosPi); + yield return Create(TensorPrimitives.AcosPi, TensorSpan.AcosPiInPlace); + yield return Create(TensorPrimitives.Asin, TensorSpan.Asin); + yield return Create(TensorPrimitives.Asin, TensorSpan.AsinInPlace); + yield return Create(TensorPrimitives.Asinh, TensorSpan.Asinh); + yield return Create(TensorPrimitives.Asinh, TensorSpan.AsinhInPlace); + yield return Create(TensorPrimitives.AsinPi, TensorSpan.AsinPi); + yield return Create(TensorPrimitives.AsinPi, TensorSpan.AsinPiInPlace); + yield return Create(TensorPrimitives.Atan, TensorSpan.Atan); + yield return Create(TensorPrimitives.Atan, TensorSpan.AtanInPlace); + yield return Create(TensorPrimitives.Atanh, TensorSpan.Atanh); + yield return Create(TensorPrimitives.Atanh, TensorSpan.AtanhInPlace); + yield return Create(TensorPrimitives.AtanPi, TensorSpan.AtanPi); + yield return Create(TensorPrimitives.AtanPi, TensorSpan.AtanPiInPlace); + yield return Create(TensorPrimitives.Cbrt, TensorSpan.CubeRoot); + yield return Create(TensorPrimitives.Cbrt, TensorSpan.CubeRootInPlace); + yield return Create(TensorPrimitives.Ceiling, TensorSpan.Ceiling); + yield return Create(TensorPrimitives.Ceiling, TensorSpan.CeilingInPlace); + yield return Create(TensorPrimitives.Cos, TensorSpan.Cos); + yield return Create(TensorPrimitives.Cos, TensorSpan.CosInPlace); + yield return Create(TensorPrimitives.Cosh, TensorSpan.Cosh); + yield return Create(TensorPrimitives.Cosh, TensorSpan.CoshInPlace); + yield return Create(TensorPrimitives.CosPi, TensorSpan.CosPi); + yield return Create(TensorPrimitives.CosPi, TensorSpan.CosPiInPlace); + yield return Create(TensorPrimitives.DegreesToRadians, TensorSpan.DegreesToRadians); + yield return Create(TensorPrimitives.DegreesToRadians, TensorSpan.DegreesToRadiansInPlace); + yield return Create(TensorPrimitives.Exp, TensorSpan.Exp); + yield return Create(TensorPrimitives.Exp, TensorSpan.ExpInPlace); + yield return Create(TensorPrimitives.Exp10, TensorSpan.Exp10); + yield return Create(TensorPrimitives.Exp10, TensorSpan.Exp10InPlace); + yield return Create(TensorPrimitives.Exp10M1, TensorSpan.Exp10M1); + yield return Create(TensorPrimitives.Exp10M1, TensorSpan.Exp10M1InPlace); + yield return Create(TensorPrimitives.Exp2, TensorSpan.Exp2); + yield return Create(TensorPrimitives.Exp2, TensorSpan.Exp2InPlace); + yield return Create(TensorPrimitives.Exp2M1, TensorSpan.Exp2M1); + yield return Create(TensorPrimitives.Exp2M1, TensorSpan.Exp2M1InPlace); + yield return Create(TensorPrimitives.ExpM1, TensorSpan.ExpM1); + yield return Create(TensorPrimitives.ExpM1, TensorSpan.ExpM1InPlace); + yield return Create(TensorPrimitives.Floor, TensorSpan.Floor); + yield return Create(TensorPrimitives.Floor, TensorSpan.FloorInPlace); + yield return Create(TensorPrimitives.LeadingZeroCount, TensorSpan.LeadingZeroCount); + yield return Create(TensorPrimitives.LeadingZeroCount, TensorSpan.LeadingZeroCount); + yield return Create(TensorPrimitives.Log, TensorSpan.Log); + yield return Create(TensorPrimitives.Log, TensorSpan.LogInPlace); + yield return Create(TensorPrimitives.Log10, TensorSpan.Log10); + yield return Create(TensorPrimitives.Log10, TensorSpan.Log10InPlace); + yield return Create(TensorPrimitives.Log10P1, TensorSpan.Log10P1); + yield return Create(TensorPrimitives.Log10P1, TensorSpan.Log10P1InPlace); + yield return Create(TensorPrimitives.Log2, TensorSpan.Log2); + yield return Create(TensorPrimitives.Log2, TensorSpan.Log2InPlace); + yield return Create(TensorPrimitives.Log2P1, TensorSpan.Log2P1); + yield return Create(TensorPrimitives.Log2P1, TensorSpan.Log2P1InPlace); + yield return Create(TensorPrimitives.LogP1, TensorSpan.LogP1); + yield return Create(TensorPrimitives.LogP1, TensorSpan.LogP1InPlace); + yield return Create(TensorPrimitives.Negate, TensorSpan.Negate); + yield return Create(TensorPrimitives.Negate, TensorSpan.NegateInPlace); + yield return Create(TensorPrimitives.OnesComplement, TensorSpan.OnesComplement); + yield return Create(TensorPrimitives.OnesComplement, TensorSpan.OnesComplementInPlace); + yield return Create(TensorPrimitives.PopCount, TensorSpan.PopCount); + yield return Create(TensorPrimitives.PopCount, TensorSpan.PopCountInPlace); + yield return Create(TensorPrimitives.RadiansToDegrees, TensorSpan.RadiansToDegrees); + yield return Create(TensorPrimitives.RadiansToDegrees, TensorSpan.RadiansToDegreesInPlace); + yield return Create(TensorPrimitives.Reciprocal, TensorSpan.Reciprocal); + yield return Create(TensorPrimitives.Reciprocal, TensorSpan.ReciprocalInPlace); + yield return Create(TensorPrimitives.Round, TensorSpan.Round); + yield return Create(TensorPrimitives.Round, TensorSpan.RoundInPlace); + yield return Create(TensorPrimitives.Sigmoid, TensorSpan.Sigmoid); + yield return Create(TensorPrimitives.Sigmoid, TensorSpan.SigmoidInPlace); + yield return Create(TensorPrimitives.Sin, TensorSpan.Sin); + yield return Create(TensorPrimitives.Sin, TensorSpan.SinInPlace); + yield return Create(TensorPrimitives.Sinh, TensorSpan.Sinh); + yield return Create(TensorPrimitives.Sinh, TensorSpan.SinhInPlace); + yield return Create(TensorPrimitives.SinPi, TensorSpan.SinPi); + yield return Create(TensorPrimitives.SinPi, TensorSpan.SinPiInPlace); + yield return Create(TensorPrimitives.SoftMax, TensorSpan.SoftMax); + yield return Create(TensorPrimitives.SoftMax, TensorSpan.SoftMaxInPlace); + yield return Create(TensorPrimitives.Sqrt, TensorSpan.Sqrt); + yield return Create(TensorPrimitives.Sqrt, TensorSpan.SqrtInPlace); + yield return Create(TensorPrimitives.Tan, TensorSpan.Tan); + yield return Create(TensorPrimitives.Tan, TensorSpan.TanInPlace); + yield return Create(TensorPrimitives.Tanh, TensorSpan.Tanh); + yield return Create(TensorPrimitives.Tanh, TensorSpan.TanhInPlace); + yield return Create(TensorPrimitives.TanPi, TensorSpan.TanPi); + yield return Create(TensorPrimitives.TanPi, TensorSpan.TanPiInPlace); + yield return Create(TensorPrimitives.Truncate, TensorSpan.Truncate); + yield return Create(TensorPrimitives.Truncate, TensorSpan.TruncateInPlace); + + static object[] Create(TensorPrimitivesSpanInSpanOut tensorPrimitivesMethod, TensorSpanInSpanOut tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(SpanInSpanOutData))] + public void TensorExtensionsSpanInSpanOut(TensorPrimitivesSpanInSpanOut tensorPrimitivesOperation, TensorSpanInSpanOut tensorOperation) + where T : INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data = new T[length]; + T[] expectedOutput = new T[length]; + + FillTensor(data); + TensorSpan x = Tensor.Create(data, tensorLength, []); + tensorPrimitivesOperation((ReadOnlySpan)data, expectedOutput); + TensorSpan results = tensorOperation(x); + + Assert.Equal(tensorLength, results.Lengths); + nint[] startingIndex = new nint[tensorLength.Length]; + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref results[startingIndex], (int)length); + + for (int i = 0; i < data.Length; i++) + { + Assert.Equal(expectedOutput[i], span[i]); + } + }); + } + + public delegate T TensorPrimitivesSpanInTOut(ReadOnlySpan input); + public delegate T TensorSpanInTOut(TensorSpan input); + public static IEnumerable SpanInFloatOutData() + { + yield return Create(TensorPrimitives.Max, TensorSpan.Max); + yield return Create(TensorPrimitives.MaxMagnitude, TensorSpan.MaxMagnitude); + yield return Create(TensorPrimitives.MaxNumber, TensorSpan.MaxNumber); + yield return Create(TensorPrimitives.Min, TensorSpan.Min); + yield return Create(TensorPrimitives.MinMagnitude, TensorSpan.MinMagnitude); + yield return Create(TensorPrimitives.MinNumber, TensorSpan.MinNumber); + yield return Create(TensorPrimitives.Norm, TensorSpan.Norm); + yield return Create(TensorPrimitives.Product, TensorSpan.Product); + yield return Create(TensorPrimitives.Sum, TensorSpan.Sum); + + static object[] Create(TensorPrimitivesSpanInTOut tensorPrimitivesMethod, TensorSpanInTOut tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(SpanInFloatOutData))] + public void TensorExtensionsSpanInTOut(TensorPrimitivesSpanInTOut tensorPrimitivesOperation, TensorSpanInTOut tensorOperation) + where T : INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data = new T[length]; + + FillTensor(data); + Tensor x = Tensor.Create(data, tensorLength, []); + T expectedOutput = tensorPrimitivesOperation((ReadOnlySpan)data); + T results = tensorOperation(x); + + Assert.Equal(expectedOutput, results); + }); + } + + public delegate void TensorPrimitivesTwoSpanInSpanOut(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output); + public delegate TensorSpan TensorTwoSpanInSpanOut(TensorSpan input, TensorSpan inputTwo); + public static IEnumerable TwoSpanInSpanOutData() + { + yield return Create(TensorPrimitives.Add, TensorSpan.Add); + yield return Create(TensorPrimitives.Add, TensorSpan.AddInPlace); + yield return Create(TensorPrimitives.Atan2, TensorSpan.Atan2); + yield return Create(TensorPrimitives.Atan2, TensorSpan.Atan2InPlace); + yield return Create(TensorPrimitives.Atan2Pi, TensorSpan.Atan2Pi); + yield return Create(TensorPrimitives.Atan2Pi, TensorSpan.Atan2PiInPlace); + yield return Create(TensorPrimitives.CopySign, TensorSpan.CopySign); + yield return Create(TensorPrimitives.CopySign, TensorSpan.CopySignInPlace); + yield return Create(TensorPrimitives.Divide, TensorSpan.Divide); + yield return Create(TensorPrimitives.Divide, TensorSpan.DivideInPlace); + yield return Create(TensorPrimitives.Hypot, TensorSpan.Hypotenuse); + yield return Create(TensorPrimitives.Hypot, TensorSpan.HypotenuseInPlace); + yield return Create(TensorPrimitives.Ieee754Remainder, TensorSpan.Ieee754Remainder); + yield return Create(TensorPrimitives.Ieee754Remainder, TensorSpan.Ieee754RemainderInPlace); + yield return Create(TensorPrimitives.Multiply, TensorSpan.Multiply); + yield return Create(TensorPrimitives.Multiply, TensorSpan.MultiplyInPlace); + yield return Create(TensorPrimitives.Pow, TensorSpan.Pow); + yield return Create(TensorPrimitives.Pow, TensorSpan.PowInPlace); + yield return Create(TensorPrimitives.Subtract, TensorSpan.Subtract); + yield return Create(TensorPrimitives.Subtract, TensorSpan.SubtractInPlace); + + static object[] Create(TensorPrimitivesTwoSpanInSpanOut tensorPrimitivesMethod, TensorTwoSpanInSpanOut tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(TwoSpanInSpanOutData))] + public void TensorExtensionsTwoSpanInSpanOut(TensorPrimitivesTwoSpanInSpanOut tensorPrimitivesOperation, TensorTwoSpanInSpanOut tensorOperation) + where T : INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data1 = new T[length]; + T[] data2 = new T[length]; + T[] expectedOutput = new T[length]; + + FillTensor(data1); + FillTensor(data2); + TensorSpan x = Tensor.Create(data1, tensorLength, []); + TensorSpan y = Tensor.Create(data2, tensorLength, []); + tensorPrimitivesOperation((ReadOnlySpan)data1, data2, expectedOutput); + TensorSpan results = tensorOperation(x, y); + + Assert.Equal(tensorLength, results.Lengths); + nint[] startingIndex = new nint[tensorLength.Length]; + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref results[startingIndex], (int)length); + + for (int i = 0; i < data1.Length; i++) + { + Assert.Equal(expectedOutput[i], span[i]); + } + }); + } + + public delegate T TensorPrimitivesTwoSpanInTOut(ReadOnlySpan input, ReadOnlySpan inputTwo); + public delegate T TensorTwoSpanInTOut(TensorSpan input, TensorSpan inputTwo); + public static IEnumerable TwoSpanInFloatOutData() + { + yield return Create(TensorPrimitives.Distance, TensorSpan.Distance); + yield return Create(TensorPrimitives.Dot, TensorSpan.Dot); + + static object[] Create(TensorPrimitivesTwoSpanInTOut tensorPrimitivesMethod, TensorTwoSpanInTOut tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(TwoSpanInFloatOutData))] + public void TensorExtensionsTwoSpanInFloatOut(TensorPrimitivesTwoSpanInTOut tensorPrimitivesOperation, TensorTwoSpanInTOut tensorOperation) + where T : INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data1 = new T[length]; + T[] data2 = new T[length]; + + FillTensor(data1); + FillTensor(data2); + TensorSpan x = Tensor.Create(data1, tensorLength, []); + TensorSpan y = Tensor.Create(data2, tensorLength, []); + T expectedOutput = tensorPrimitivesOperation((ReadOnlySpan)data1, data2); + T results = tensorOperation(x, y); + + Assert.Equal(expectedOutput, results); + }); + } + + #endregion + [Fact] public static void TensorSpanSystemArrayConstructorTests() { diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs index f5f61cf936856..d3a36377f32ca 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs @@ -1,18 +1,290 @@ // 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.Collections.Generic; using System.Linq; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.InteropServices; using Xunit; namespace System.Numerics.Tensors.Tests { public class TensorTests { + #region TensorPrimitivesForwardsTests + private void FillTensor(Span span) + where T : INumberBase + { + for (int i = 0; i < span.Length; i++) + { + span[i] = T.CreateChecked((Random.Shared.NextSingle() * 100) - 50); + } + } + + private static nint CalculateTotalLength(ReadOnlySpan lengths) + { + if (lengths.IsEmpty) + return 0; + nint totalLength = 1; + for (int i = 0; i < lengths.Length; i++) + { + totalLength *= lengths[i]; + } + + return totalLength; + } + + public delegate void PerformCalculationSpanInSpanOut(ReadOnlySpan input, Span output); + + public static IEnumerable SpanInSpanOutData() + { + yield return Create(TensorPrimitives.Abs, Tensor.Abs); + yield return Create(TensorPrimitives.Abs, Tensor.AbsInPlace); + yield return Create(TensorPrimitives.Acos, Tensor.Acos); + yield return Create(TensorPrimitives.Acos, Tensor.AcosInPlace); + yield return Create(TensorPrimitives.Acosh, Tensor.Acosh); + yield return Create(TensorPrimitives.Acosh, Tensor.AcoshInPlace); + yield return Create(TensorPrimitives.AcosPi, Tensor.AcosPi); + yield return Create(TensorPrimitives.AcosPi, Tensor.AcosPiInPlace); + yield return Create(TensorPrimitives.Asin, Tensor.Asin); + yield return Create(TensorPrimitives.Asin, Tensor.AsinInPlace); + yield return Create(TensorPrimitives.Asinh, Tensor.Asinh); + yield return Create(TensorPrimitives.Asinh, Tensor.AsinhInPlace); + yield return Create(TensorPrimitives.AsinPi, Tensor.AsinPi); + yield return Create(TensorPrimitives.AsinPi, Tensor.AsinPiInPlace); + yield return Create(TensorPrimitives.Atan, Tensor.Atan); + yield return Create(TensorPrimitives.Atan, Tensor.AtanInPlace); + yield return Create(TensorPrimitives.Atanh, Tensor.Atanh); + yield return Create(TensorPrimitives.Atanh, Tensor.AtanhInPlace); + yield return Create(TensorPrimitives.AtanPi, Tensor.AtanPi); + yield return Create(TensorPrimitives.AtanPi, Tensor.AtanPiInPlace); + yield return Create(TensorPrimitives.Cbrt, Tensor.CubeRoot); + yield return Create(TensorPrimitives.Cbrt, Tensor.CubeRootInPlace); + yield return Create(TensorPrimitives.Ceiling, Tensor.Ceiling); + yield return Create(TensorPrimitives.Ceiling, Tensor.CeilingInPlace); + yield return Create(TensorPrimitives.Cos, Tensor.Cos); + yield return Create(TensorPrimitives.Cos, Tensor.CosInPlace); + yield return Create(TensorPrimitives.Cosh, Tensor.Cosh); + yield return Create(TensorPrimitives.Cosh, Tensor.CoshInPlace); + yield return Create(TensorPrimitives.CosPi, Tensor.CosPi); + yield return Create(TensorPrimitives.CosPi, Tensor.CosPiInPlace); + yield return Create(TensorPrimitives.DegreesToRadians, Tensor.DegreesToRadians); + yield return Create(TensorPrimitives.DegreesToRadians, Tensor.DegreesToRadiansInPlace); + yield return Create(TensorPrimitives.Exp, Tensor.Exp); + yield return Create(TensorPrimitives.Exp, Tensor.ExpInPlace); + yield return Create(TensorPrimitives.Exp10, Tensor.Exp10); + yield return Create(TensorPrimitives.Exp10, Tensor.Exp10InPlace); + yield return Create(TensorPrimitives.Exp10M1, Tensor.Exp10M1); + yield return Create(TensorPrimitives.Exp10M1, Tensor.Exp10M1InPlace); + yield return Create(TensorPrimitives.Exp2, Tensor.Exp2); + yield return Create(TensorPrimitives.Exp2, Tensor.Exp2InPlace); + yield return Create(TensorPrimitives.Exp2M1, Tensor.Exp2M1); + yield return Create(TensorPrimitives.Exp2M1, Tensor.Exp2M1InPlace); + yield return Create(TensorPrimitives.ExpM1, Tensor.ExpM1); + yield return Create(TensorPrimitives.ExpM1, Tensor.ExpM1InPlace); + yield return Create(TensorPrimitives.Floor, Tensor.Floor); + yield return Create(TensorPrimitives.Floor, Tensor.FloorInPlace); + yield return Create(TensorPrimitives.LeadingZeroCount, Tensor.LeadingZeroCount); + yield return Create(TensorPrimitives.LeadingZeroCount, Tensor.LeadingZeroCount); + yield return Create(TensorPrimitives.Log, Tensor.Log); + yield return Create(TensorPrimitives.Log, Tensor.LogInPlace); + yield return Create(TensorPrimitives.Log10, Tensor.Log10); + yield return Create(TensorPrimitives.Log10, Tensor.Log10InPlace); + yield return Create(TensorPrimitives.Log10P1, Tensor.Log10P1); + yield return Create(TensorPrimitives.Log10P1, Tensor.Log10P1InPlace); + yield return Create(TensorPrimitives.Log2, Tensor.Log2); + yield return Create(TensorPrimitives.Log2, Tensor.Log2InPlace); + yield return Create(TensorPrimitives.Log2P1, Tensor.Log2P1); + yield return Create(TensorPrimitives.Log2P1, Tensor.Log2P1InPlace); + yield return Create(TensorPrimitives.LogP1, Tensor.LogP1); + yield return Create(TensorPrimitives.LogP1, Tensor.LogP1InPlace); + yield return Create(TensorPrimitives.Negate, Tensor.Negate); + yield return Create(TensorPrimitives.Negate, Tensor.NegateInPlace); + yield return Create(TensorPrimitives.OnesComplement, Tensor.OnesComplement); + yield return Create(TensorPrimitives.OnesComplement, Tensor.OnesComplementInPlace); + yield return Create(TensorPrimitives.PopCount, Tensor.PopCount); + yield return Create(TensorPrimitives.PopCount, Tensor.PopCountInPlace); + yield return Create(TensorPrimitives.RadiansToDegrees, Tensor.RadiansToDegrees); + yield return Create(TensorPrimitives.RadiansToDegrees, Tensor.RadiansToDegreesInPlace); + yield return Create(TensorPrimitives.Reciprocal, Tensor.Reciprocal); + yield return Create(TensorPrimitives.Reciprocal, Tensor.ReciprocalInPlace); + yield return Create(TensorPrimitives.Round, Tensor.Round); + yield return Create(TensorPrimitives.Round, Tensor.RoundInPlace); + yield return Create(TensorPrimitives.Sigmoid, Tensor.Sigmoid); + yield return Create(TensorPrimitives.Sigmoid, Tensor.SigmoidInPlace); + yield return Create(TensorPrimitives.Sin, Tensor.Sin); + yield return Create(TensorPrimitives.Sin, Tensor.SinInPlace); + yield return Create(TensorPrimitives.Sinh, Tensor.Sinh); + yield return Create(TensorPrimitives.Sinh, Tensor.SinhInPlace); + yield return Create(TensorPrimitives.SinPi, Tensor.SinPi); + yield return Create(TensorPrimitives.SinPi, Tensor.SinPiInPlace); + yield return Create(TensorPrimitives.SoftMax, Tensor.SoftMax); + yield return Create(TensorPrimitives.SoftMax, Tensor.SoftMaxInPlace); + yield return Create(TensorPrimitives.Sqrt, Tensor.Sqrt); + yield return Create(TensorPrimitives.Sqrt, Tensor.SqrtInPlace); + yield return Create(TensorPrimitives.Tan, Tensor.Tan); + yield return Create(TensorPrimitives.Tan, Tensor.TanInPlace); + yield return Create(TensorPrimitives.Tanh, Tensor.Tanh); + yield return Create(TensorPrimitives.Tanh, Tensor.TanhInPlace); + yield return Create(TensorPrimitives.TanPi, Tensor.TanPi); + yield return Create(TensorPrimitives.TanPi, Tensor.TanPiInPlace); + yield return Create(TensorPrimitives.Truncate, Tensor.Truncate); + yield return Create(TensorPrimitives.Truncate, Tensor.TruncateInPlace); + + static object[] Create(PerformCalculationSpanInSpanOut tensorPrimitivesMethod, Func, Tensor> tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(SpanInSpanOutData))] + public void TensorExtensionsSpanInSpanOut(PerformCalculationSpanInSpanOut tensorPrimitivesOperation, Func, Tensor> tensorOperation) + where T: INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data = new T[length]; + T[] expectedOutput = new T[length]; + + FillTensor(data); + Tensor x = Tensor.Create(data, tensorLength, []); + tensorPrimitivesOperation((ReadOnlySpan)data, expectedOutput); + Tensor results = tensorOperation(x); + + Assert.Equal(tensorLength, results.Lengths); + nint[] startingIndex = new nint[tensorLength.Length]; + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref results[startingIndex], (int)length); + + for (int i = 0; i < data.Length; i++) + { + Assert.Equal(expectedOutput[i], span[i]); + } + }); + } + + public delegate T PerformCalculationSpanInTOut(ReadOnlySpan input); + public static IEnumerable SpanInFloatOutData() + { + yield return Create(TensorPrimitives.Max, Tensor.Max); + yield return Create(TensorPrimitives.MaxMagnitude, Tensor.MaxMagnitude); + yield return Create(TensorPrimitives.MaxNumber, Tensor.MaxNumber); + yield return Create(TensorPrimitives.Min, Tensor.Min); + yield return Create(TensorPrimitives.MinMagnitude, Tensor.MinMagnitude); + yield return Create(TensorPrimitives.MinNumber, Tensor.MinNumber); + yield return Create(TensorPrimitives.Norm, Tensor.Norm); + yield return Create(TensorPrimitives.Product, Tensor.Product); + yield return Create(TensorPrimitives.Sum, Tensor.Sum); + + static object[] Create(PerformCalculationSpanInTOut tensorPrimitivesMethod, Func, T> tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(SpanInFloatOutData))] + public void TensorExtensionsSpanInTOut(PerformCalculationSpanInTOut tensorPrimitivesOperation, Func, T> tensorOperation) + where T : INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data = new T[length]; + + FillTensor(data); + Tensor x = Tensor.Create(data, tensorLength, []); + T expectedOutput = tensorPrimitivesOperation((ReadOnlySpan)data); + T results = tensorOperation(x); + + Assert.Equal(expectedOutput, results); + }); + } + + public delegate void PerformCalculationTwoSpanInSpanOut(ReadOnlySpan input, ReadOnlySpan inputTwo, Span output); + public static IEnumerable TwoSpanInSpanOutData() + { + yield return Create(TensorPrimitives.Add, Tensor.Add); + yield return Create(TensorPrimitives.Add, Tensor.AddInPlace); + yield return Create(TensorPrimitives.Atan2, Tensor.Atan2); + yield return Create(TensorPrimitives.Atan2, Tensor.Atan2InPlace); + yield return Create(TensorPrimitives.Atan2Pi, Tensor.Atan2Pi); + yield return Create(TensorPrimitives.Atan2Pi, Tensor.Atan2PiInPlace); + yield return Create(TensorPrimitives.CopySign, Tensor.CopySign); + yield return Create(TensorPrimitives.CopySign, Tensor.CopySignInPlace); + yield return Create(TensorPrimitives.Divide, Tensor.Divide); + yield return Create(TensorPrimitives.Divide, Tensor.DivideInPlace); + yield return Create(TensorPrimitives.Hypot, Tensor.Hypotenuse); + yield return Create(TensorPrimitives.Hypot, Tensor.HypotenuseInPlace); + yield return Create(TensorPrimitives.Ieee754Remainder, Tensor.Ieee754Remainder); + yield return Create(TensorPrimitives.Ieee754Remainder, Tensor.Ieee754RemainderInPlace); + yield return Create(TensorPrimitives.Multiply, Tensor.Multiply); + yield return Create(TensorPrimitives.Multiply, Tensor.MultiplyInPlace); + yield return Create(TensorPrimitives.Pow, Tensor.Pow); + yield return Create(TensorPrimitives.Pow, Tensor.PowInPlace); + yield return Create(TensorPrimitives.Subtract, Tensor.Subtract); + yield return Create(TensorPrimitives.Subtract, Tensor.SubtractInPlace); + + static object[] Create(PerformCalculationTwoSpanInSpanOut tensorPrimitivesMethod, Func, Tensor, Tensor> tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(TwoSpanInSpanOutData))] + public void TensorExtensionsTwoSpanInSpanOut(PerformCalculationTwoSpanInSpanOut tensorPrimitivesOperation, Func, Tensor, Tensor> tensorOperation) + where T: INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data1 = new T[length]; + T[] data2 = new T[length]; + T[] expectedOutput = new T[length]; + + FillTensor(data1); + FillTensor(data2); + Tensor x = Tensor.Create(data1, tensorLength, []); + Tensor y = Tensor.Create(data2, tensorLength, []); + tensorPrimitivesOperation((ReadOnlySpan)data1, data2, expectedOutput); + Tensor results = tensorOperation(x, y); + + Assert.Equal(tensorLength, results.Lengths); + nint[] startingIndex = new nint[tensorLength.Length]; + ReadOnlySpan span = MemoryMarshal.CreateSpan(ref results[startingIndex], (int)length); + + for (int i = 0; i < data1.Length; i++) + { + Assert.Equal(expectedOutput[i], span[i]); + } + }); + } + + public delegate T PerformCalculationTwoSpanInFloatOut(ReadOnlySpan input, ReadOnlySpan inputTwo); + public static IEnumerable TwoSpanInFloatOutData() + { + yield return Create(TensorPrimitives.Distance, Tensor.Distance); + yield return Create(TensorPrimitives.Dot, Tensor.Dot); + + static object[] Create(PerformCalculationTwoSpanInFloatOut tensorPrimitivesMethod, Func, Tensor, T> tensorOperation) + => new object[] { tensorPrimitivesMethod, tensorOperation }; + } + + [Theory, MemberData(nameof(TwoSpanInFloatOutData))] + public void TensorExtensionsTwoSpanInFloatOut(PerformCalculationTwoSpanInFloatOut tensorPrimitivesOperation, Func, Tensor, T> tensorOperation) + where T: INumberBase + { + Assert.All(Helpers.TensorShapes, tensorLength => + { + nint length = CalculateTotalLength(tensorLength); + T[] data1 = new T[length]; + T[] data2 = new T[length]; + + FillTensor(data1); + FillTensor(data2); + Tensor x = Tensor.Create(data1, tensorLength, []); + Tensor y = Tensor.Create(data2, tensorLength, []); + T expectedOutput = tensorPrimitivesOperation((ReadOnlySpan)data1, data2); + T results = tensorOperation(x, y); + + Assert.Equal(expectedOutput, results); + }); + } + + #endregion + [Fact] public static void TensorFactoryCreateUninitializedTests() { From fe754dbede94750d5a1e4c19b3e647f696abe099 Mon Sep 17 00:00:00 2001 From: Michael Sharp Date: Fri, 7 Jun 2024 12:21:55 -0600 Subject: [PATCH 5/5] test fixes and ref fixes --- .../ref/System.Numerics.Tensors.netcore.cs | 4 ++-- .../System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs | 6 +++--- .../src/System/Numerics/Tensors/netcore/Tensor.cs | 2 +- .../src/System/Numerics/Tensors/netcore/TensorSpan.cs | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs index bb7bd1d57d694..7897a41ee6ce2 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs @@ -55,7 +55,7 @@ namespace System.Buffers } namespace System.Numerics.Tensors { - public partial interface IReadOnlyTensor : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable where TSelf : System.Numerics.Tensors.IReadOnlyTensor + public partial interface IReadOnlyTensor : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable where TSelf : System.Numerics.Tensors.IReadOnlyTensor { static abstract TSelf? Empty { get; } nint FlattenedLength { get; } @@ -707,7 +707,7 @@ public void Clear() { } public void CopyTo(scoped System.Numerics.Tensors.TensorSpan destination) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("Equals() on TensorSpan will always throw an exception. Use the equality operator instead.")] - #pragma warning disable CS0809 // Obsolete member overrides non-obsolete member +#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member public override bool Equals(object? obj) { throw null; } #pragma warning restore CS0809 // Obsolete member overrides non-obsolete member public void Fill(T value) { } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs index 57ec96024c27b..bad5e28d41ecf 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/ReadOnlyTensorSpan.cs @@ -105,7 +105,7 @@ public ReadOnlyTensorSpan(T[]? array, int start, scoped ReadOnlySpan lengt } else { - if (((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) && array.Length != 0) + if (((uint)start > (uint)array.Length || (uint)maxElements >= (uint)(array.Length - start)) && array.Length != 0) ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); } @@ -196,7 +196,7 @@ public ReadOnlyTensorSpan(Array? array, scoped ReadOnlySpan start, scoped R } else { - if (((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) && array.Length != 0) + if (((uint)startOffset > (uint)array.Length || (uint)maxElements >= (uint)(array.Length - startOffset)) && array.Length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); } @@ -245,7 +245,7 @@ public ReadOnlyTensorSpan(Array? array, scoped ReadOnlySpan startIndex, } else { - if ((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) + if ((uint)startOffset > (uint)array.Length || (uint)maxElements >= (uint)(array.Length - startOffset)) ThrowHelper.ThrowArgumentOutOfRangeException(); } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs index 50007fcaedb45..34311af8aa94a 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs @@ -75,7 +75,7 @@ internal Tensor(T[]? values, ReadOnlySpan lengths, ReadOnlySpan stri } else { - if (((uint)maxElements > (uint)(values.Length)) && values.Length != 0) + if (((uint)maxElements >= (uint)(values.Length)) && values.Length != 0) ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs index c92c243bf3a88..b6e8826cb2556 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorSpan.cs @@ -107,7 +107,7 @@ public TensorSpan(T[]? array, int start, scoped ReadOnlySpan lengths, scop } else { - if (((uint)start > (uint)array.Length || (uint)maxElements > (uint)(array.Length - start)) && array.Length != 0) + if (((uint)start > (uint)array.Length || (uint)maxElements >= (uint)(array.Length - start)) && array.Length != 0) ThrowHelper.ThrowArgument_InvalidStridesAndLengths(); } @@ -200,7 +200,7 @@ public TensorSpan(Array? array, scoped ReadOnlySpan start, scoped ReadOnlyS } else { - if (((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) && array.Length != 0) + if (((uint)startOffset > (uint)array.Length || (uint)maxElements >= (uint)(array.Length - startOffset)) && array.Length != 0) ThrowHelper.ThrowArgumentOutOfRangeException(); } @@ -248,7 +248,7 @@ public TensorSpan(Array? array, scoped ReadOnlySpan startIndex, scoped R } else { - if ((uint)startOffset > (uint)array.Length || (uint)maxElements > (uint)(array.Length - startOffset)) + if ((uint)startOffset > (uint)array.Length || (uint)maxElements >= (uint)(array.Length - startOffset)) ThrowHelper.ThrowArgumentOutOfRangeException(); }