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 40fcdafe65436..e7945587afef4 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 @@ -89,12 +89,18 @@ public static partial class TensorPrimitives public static T Max(System.ReadOnlySpan x) where T : System.Numerics.INumber { throw null; } public static void Max(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) where T : System.Numerics.INumber { } public static void Max(System.ReadOnlySpan x, T y, System.Span destination) where T : System.Numerics.INumber { } + public static T MaxNumber(System.ReadOnlySpan x) where T : System.Numerics.INumber { throw null; } + public static void MaxNumber(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) where T : System.Numerics.INumber { } + public static void MaxNumber(System.ReadOnlySpan x, T y, System.Span destination) where T : System.Numerics.INumber { } public static T MinMagnitude(System.ReadOnlySpan x) where T : System.Numerics.INumberBase { throw null; } public static void MinMagnitude(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) where T : System.Numerics.INumberBase { } public static void MinMagnitude(System.ReadOnlySpan x, T y, System.Span destination) where T : System.Numerics.INumberBase { } public static T Min(System.ReadOnlySpan x) where T : System.Numerics.INumber { throw null; } public static void Min(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) where T : System.Numerics.INumber { } public static void Min(System.ReadOnlySpan x, T y, System.Span destination) where T : System.Numerics.INumber { } + public static T MinNumber(System.ReadOnlySpan x) where T : System.Numerics.INumber { throw null; } + public static void MinNumber(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) where T : System.Numerics.INumber { } + public static void MinNumber(System.ReadOnlySpan x, T y, System.Span destination) where T : System.Numerics.INumber { } public static void MultiplyAdd(System.ReadOnlySpan x, System.ReadOnlySpan y, System.ReadOnlySpan addend, System.Span destination) where T : System.Numerics.IAdditionOperators, System.Numerics.IMultiplyOperators { } public static void MultiplyAdd(System.ReadOnlySpan x, System.ReadOnlySpan y, T addend, System.Span destination) where T : System.Numerics.IAdditionOperators, System.Numerics.IMultiplyOperators { } public static void MultiplyAdd(System.ReadOnlySpan x, T y, System.ReadOnlySpan addend, System.Span destination) where T : System.Numerics.IAdditionOperators, System.Numerics.IMultiplyOperators { } 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 f5bb6c851dfb0..bc0e5be9bed57 100644 --- a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) @@ -82,8 +82,10 @@ + + diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs index 0e0566f2d935a..2e760e30fb7c6 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs @@ -96,35 +96,21 @@ public static T Invoke(T x, T y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (AdvSimd.IsSupported) - { - if (typeof(T) == typeof(byte)) return AdvSimd.Max(x.AsByte(), y.AsByte()).As(); - if (typeof(T) == typeof(sbyte)) return AdvSimd.Max(x.AsSByte(), y.AsSByte()).As(); - if (typeof(T) == typeof(short)) return AdvSimd.Max(x.AsInt16(), y.AsInt16()).As(); - if (typeof(T) == typeof(ushort)) return AdvSimd.Max(x.AsUInt16(), y.AsUInt16()).As(); - if (typeof(T) == typeof(int)) return AdvSimd.Max(x.AsInt32(), y.AsInt32()).As(); - if (typeof(T) == typeof(uint)) return AdvSimd.Max(x.AsUInt32(), y.AsUInt32()).As(); - if (typeof(T) == typeof(float)) return AdvSimd.Max(x.AsSingle(), y.AsSingle()).As(); - } - - if (AdvSimd.Arm64.IsSupported) + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { - if (typeof(T) == typeof(double)) return AdvSimd.Arm64.Max(x.AsDouble(), y.AsDouble()).As(); - } + if (AdvSimd.IsSupported && typeof(T) == typeof(float)) + { + return AdvSimd.Max(x.AsSingle(), y.AsSingle()).As(); + } - if (typeof(T) == typeof(float)) - { - return - Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(x.AsSingle()).As(), y, x), - Vector128.Max(x, y)); - } + if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) + { + return AdvSimd.Arm64.Max(x.AsDouble(), y.AsDouble()).As(); + } - if (typeof(T) == typeof(double)) - { return Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(x.AsDouble()).As(), y, x), + Vector128.ConditionalSelect(IsNegative(x), y, x), Vector128.Max(x, y)); } @@ -134,19 +120,11 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y) { - if (typeof(T) == typeof(float)) - { - return - Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(x.AsSingle()).As(), y, x), - Vector256.Max(x, y)); - } - - if (typeof(T) == typeof(double)) + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { return Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(x.AsDouble()).As(), y, x), + Vector256.ConditionalSelect(IsNegative(x), y, x), Vector256.Max(x, y)); } @@ -156,19 +134,11 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y) { - if (typeof(T) == typeof(float)) - { - return - Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(x.AsSingle()).As(), y, x), - Vector512.Max(x, y)); - } - - if (typeof(T) == typeof(double)) + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { return Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(x.AsDouble()).As(), y, x), + Vector512.ConditionalSelect(IsNegative(x), y, x), Vector512.Max(x, y)); } @@ -192,24 +162,18 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (AdvSimd.IsSupported) + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { - if (typeof(T) == typeof(byte)) return AdvSimd.Max(x.AsByte(), y.AsByte()).As(); - if (typeof(T) == typeof(sbyte)) return AdvSimd.Max(x.AsSByte(), y.AsSByte()).As(); - if (typeof(T) == typeof(ushort)) return AdvSimd.Max(x.AsUInt16(), y.AsUInt16()).As(); - if (typeof(T) == typeof(short)) return AdvSimd.Max(x.AsInt16(), y.AsInt16()).As(); - if (typeof(T) == typeof(uint)) return AdvSimd.Max(x.AsUInt32(), y.AsUInt32()).As(); - if (typeof(T) == typeof(int)) return AdvSimd.Max(x.AsInt32(), y.AsInt32()).As(); - if (typeof(T) == typeof(float)) return AdvSimd.Max(x.AsSingle(), y.AsSingle()).As(); - } + if (AdvSimd.IsSupported && typeof(T) == typeof(float)) + { + return AdvSimd.Max(x.AsSingle(), y.AsSingle()).As(); + } - if (AdvSimd.Arm64.IsSupported) - { - if (typeof(T) == typeof(double)) return AdvSimd.Arm64.Max(x.AsDouble(), y.AsDouble()).As(); - } + if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) + { + return AdvSimd.Arm64.Max(x.AsDouble(), y.AsDouble()).As(); + } - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { return Vector128.ConditionalSelect(Vector128.Equals(x, x), Vector128.ConditionalSelect(Vector128.Equals(y, y), diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs new file mode 100644 index 0000000000000..ef4b39a77f8cb --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace System.Numerics.Tensors +{ + public static partial class TensorPrimitives + { + /// Searches for the largest number in the specified tensor. + /// The tensor, represented as a span. + /// The maximum element in . + /// Length of must be greater than zero. + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximumNumber` function. Positive 0 is considered greater than negative 0. + /// + /// + /// 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 T MaxNumber(ReadOnlySpan x) + where T : INumber => + MinMaxCore>(x); + + /// Computes the element-wise maximum of the numbers in the specified tensors. + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of must be same as length of . + /// Destination is too short. + /// and reference overlapping memory locations and do not begin at the same location. + /// and reference overlapping memory locations and do not begin at the same location. + /// + /// + /// This method effectively computes [i] = .MaxNumber([i], [i]). + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximumNumber` function. If either value is + /// the other is returned. Positive 0 is considered greater than negative 0. + /// + /// + /// 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 void MaxNumber(ReadOnlySpan x, ReadOnlySpan y, Span destination) + where T : INumber => + InvokeSpanSpanIntoSpan>(x, y, destination); + + /// Computes the element-wise maximum of the numbers in the specified tensors. + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// and reference overlapping memory locations and do not begin at the same location. + /// + /// + /// This method effectively computes [i] = .MaxNumber([i], ). + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximumNumber` function. If either value is + /// the other is returned. Positive 0 is considered greater than negative 0. + /// + /// + /// 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 void MaxNumber(ReadOnlySpan x, T y, Span destination) + where T : INumber => + InvokeSpanScalarIntoSpan>(x, y, destination); + + /// T.MaxNumber(x, y) + internal readonly struct MaxNumberOperator : IAggregationOperator where T : INumber + { + public static bool Vectorizable => true; + + public static T Invoke(T x, T y) => T.MaxNumber(x, y); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Invoke(Vector128 x, Vector128 y) + { + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + if (AdvSimd.IsSupported && typeof(T) == typeof(float)) + { + return AdvSimd.MaxNumber(x.AsSingle(), y.AsSingle()).As(); + } + + if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) + { + return AdvSimd.Arm64.MaxNumber(x.AsDouble(), y.AsDouble()).As(); + } + + return + Vector128.ConditionalSelect(Vector128.Equals(x, y), + Vector128.ConditionalSelect(IsNegative(y), x, y), + Vector128.ConditionalSelect(Vector128.Equals(y, y), Vector128.Max(x, y), x)); + } + + return Vector128.Max(x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Invoke(Vector256 x, Vector256 y) + { + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + return + Vector256.ConditionalSelect(Vector256.Equals(x, y), + Vector256.ConditionalSelect(IsNegative(y), x, y), + Vector256.ConditionalSelect(Vector256.Equals(y, y), Vector256.Max(x, y), x)); + } + + return Vector256.Max(x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Invoke(Vector512 x, Vector512 y) + { + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + return + Vector512.ConditionalSelect(Vector512.Equals(x, y), + Vector512.ConditionalSelect(IsNegative(y), x, y), + Vector512.ConditionalSelect(Vector512.Equals(y, y), Vector512.Max(x, y), x)); + } + + return Vector512.Max(x, y); + } + + public static T Invoke(Vector128 x) => HorizontalAggregate>(x); + public static T Invoke(Vector256 x) => HorizontalAggregate>(x); + public static T Invoke(Vector512 x) => HorizontalAggregate>(x); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs index faea478057982..fd3931fa3d194 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs @@ -79,24 +79,18 @@ public static T Invoke(T x, T y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (AdvSimd.IsSupported) + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { - if (typeof(T) == typeof(byte)) return AdvSimd.Min(x.AsByte(), y.AsByte()).As(); - if (typeof(T) == typeof(sbyte)) return AdvSimd.Min(x.AsSByte(), y.AsSByte()).As(); - if (typeof(T) == typeof(short)) return AdvSimd.Min(x.AsInt16(), y.AsInt16()).As(); - if (typeof(T) == typeof(ushort)) return AdvSimd.Min(x.AsUInt16(), y.AsUInt16()).As(); - if (typeof(T) == typeof(int)) return AdvSimd.Min(x.AsInt32(), y.AsInt32()).As(); - if (typeof(T) == typeof(uint)) return AdvSimd.Min(x.AsUInt32(), y.AsUInt32()).As(); - if (typeof(T) == typeof(float)) return AdvSimd.Min(x.AsSingle(), y.AsSingle()).As(); - } + if (AdvSimd.IsSupported && typeof(T) == typeof(float)) + { + return AdvSimd.Min(x.AsSingle(), y.AsSingle()).As(); + } - if (AdvSimd.Arm64.IsSupported) - { - if (typeof(T) == typeof(double)) return AdvSimd.Arm64.Min(x.AsDouble(), y.AsDouble()).As(); - } + if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) + { + return AdvSimd.Arm64.Min(x.AsDouble(), y.AsDouble()).As(); + } - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { return Vector128.ConditionalSelect(Vector128.Equals(x, y), Vector128.ConditionalSelect(IsNegative(y), y, x), @@ -149,24 +143,18 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (AdvSimd.IsSupported) + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { - if (typeof(T) == typeof(byte)) return AdvSimd.Min(x.AsByte(), y.AsByte()).As(); - if (typeof(T) == typeof(sbyte)) return AdvSimd.Min(x.AsSByte(), y.AsSByte()).As(); - if (typeof(T) == typeof(short)) return AdvSimd.Min(x.AsInt16(), y.AsInt16()).As(); - if (typeof(T) == typeof(ushort)) return AdvSimd.Min(x.AsUInt16(), y.AsUInt16()).As(); - if (typeof(T) == typeof(int)) return AdvSimd.Min(x.AsInt32(), y.AsInt32()).As(); - if (typeof(T) == typeof(uint)) return AdvSimd.Min(x.AsUInt32(), y.AsUInt32()).As(); - if (typeof(T) == typeof(float)) return AdvSimd.Min(x.AsSingle(), y.AsSingle()).As(); - } + if (AdvSimd.IsSupported && typeof(T) == typeof(float)) + { + return AdvSimd.Min(x.AsSingle(), y.AsSingle()).As(); + } - if (AdvSimd.Arm64.IsSupported) - { - if (typeof(T) == typeof(double)) return AdvSimd.Arm64.Min(x.AsDouble(), y.AsDouble()).As(); - } + if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) + { + return AdvSimd.Arm64.Min(x.AsDouble(), y.AsDouble()).As(); + } - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { return Vector128.ConditionalSelect(Vector128.Equals(x, x), Vector128.ConditionalSelect(Vector128.Equals(y, y), diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinNumber.cs new file mode 100644 index 0000000000000..ab0cb5080fab0 --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinNumber.cs @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace System.Numerics.Tensors +{ + public static partial class TensorPrimitives + { + /// Searches for the largest number in the specified tensor. + /// The tensor, represented as a span. + /// The maximum element in . + /// Length of must be greater than zero. + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximumNumber` function. Positive 0 is considered greater than negative 0. + /// + /// + /// 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 T MinNumber(ReadOnlySpan x) + where T : INumber => + MinMaxCore>(x); + + /// Computes the element-wise maximum of the numbers in the specified tensors. + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of must be same as length of . + /// Destination is too short. + /// and reference overlapping memory locations and do not begin at the same location. + /// and reference overlapping memory locations and do not begin at the same location. + /// + /// + /// This method effectively computes [i] = .MinNumber([i], [i]). + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximumNumber` function. If either value is + /// the other is returned. Positive 0 is considered greater than negative 0. + /// + /// + /// 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 void MinNumber(ReadOnlySpan x, ReadOnlySpan y, Span destination) + where T : INumber => + InvokeSpanSpanIntoSpan>(x, y, destination); + + /// Computes the element-wise maximum of the numbers in the specified tensors. + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// and reference overlapping memory locations and do not begin at the same location. + /// + /// + /// This method effectively computes [i] = .MinNumber([i], ). + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximumNumber` function. If either value is + /// the other is returned. Positive 0 is considered greater than negative 0. + /// + /// + /// 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 void MinNumber(ReadOnlySpan x, T y, Span destination) + where T : INumber => + InvokeSpanScalarIntoSpan>(x, y, destination); + + /// T.MinNumber(x, y) + internal readonly struct MinNumberOperator : IAggregationOperator where T : INumber + { + public static bool Vectorizable => true; + + public static T Invoke(T x, T y) => T.MinNumber(x, y); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Invoke(Vector128 x, Vector128 y) + { + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + if (AdvSimd.IsSupported && typeof(T) == typeof(float)) + { + return AdvSimd.MinNumber(x.AsSingle(), y.AsSingle()).As(); + } + + if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) + { + return AdvSimd.Arm64.MinNumber(x.AsDouble(), y.AsDouble()).As(); + } + + return + Vector128.ConditionalSelect(Vector128.Equals(x, y), + Vector128.ConditionalSelect(IsNegative(x), x, y), + Vector128.ConditionalSelect(Vector128.Equals(y, y), Vector128.Min(x, y), x)); + } + + return Vector128.Min(x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Invoke(Vector256 x, Vector256 y) + { + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + return + Vector256.ConditionalSelect(Vector256.Equals(x, y), + Vector256.ConditionalSelect(IsNegative(x), x, y), + Vector256.ConditionalSelect(Vector256.Equals(y, y), Vector256.Min(x, y), x)); + } + + return Vector256.Min(x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Invoke(Vector512 x, Vector512 y) + { + if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + return + Vector512.ConditionalSelect(Vector512.Equals(x, y), + Vector512.ConditionalSelect(IsNegative(x), x, y), + Vector512.ConditionalSelect(Vector512.Equals(y, y), Vector512.Min(x, y), x)); + } + + return Vector512.Min(x, y); + } + + public static T Invoke(Vector128 x) => HorizontalAggregate>(x); + public static T Invoke(Vector256 x) => HorizontalAggregate>(x); + public static T Invoke(Vector512 x) => HorizontalAggregate>(x); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs index 0cd20f1d647a4..0ad762f9401ed 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs @@ -511,6 +511,8 @@ public static IEnumerable SpanSpanDestinationFunctionsToTest() yield return Create(TensorPrimitives.Hypot, T.Hypot); yield return Create(TensorPrimitives.Ieee754Remainder, T.Ieee754Remainder); yield return Create(TensorPrimitives.Log, T.Log); + yield return Create(TensorPrimitives.MaxNumber, T.MaxNumber); + yield return Create(TensorPrimitives.MinNumber, T.MinNumber); yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance(doubleTolerance: 1e-13, floatTolerance: 1e-5f)); static object[] Create(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) @@ -644,8 +646,10 @@ public static IEnumerable SpanScalarDestinationFunctionsToTest() yield return Create(TensorPrimitives.Log, T.Log); yield return Create(TensorPrimitives.Max, T.Max); yield return Create(TensorPrimitives.MaxMagnitude, T.MaxMagnitude); + yield return Create(TensorPrimitives.MaxNumber, T.MaxNumber); yield return Create(TensorPrimitives.Min, T.Min); yield return Create(TensorPrimitives.MinMagnitude, T.MinMagnitude); + yield return Create(TensorPrimitives.MinNumber, T.MinNumber); static object[] Create(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) => new object[] { tensorPrimitivesMethod, expectedMethod, tolerance }; @@ -1806,8 +1810,10 @@ public static IEnumerable SpanScalarDestinationFunctionsToTest() yield return Create(TensorPrimitives.BitwiseOr, (x, y) => x | y); yield return Create(TensorPrimitives.Max, T.Max); yield return Create(TensorPrimitives.MaxMagnitude, T.MaxMagnitude); + yield return Create(TensorPrimitives.MaxNumber, T.MaxNumber); yield return Create(TensorPrimitives.Min, T.Min); yield return Create(TensorPrimitives.MinMagnitude, T.MinMagnitude); + yield return Create(TensorPrimitives.MinNumber, T.MinNumber); yield return Create(TensorPrimitives.Xor, (x, y) => x ^ y); static object[] Create(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod)