Skip to content

Commit

Permalink
Add TensorPrimitives.{Max/Min}MagnitudeNumber (#104651)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed Jul 10, 2024
1 parent 029007d commit d40ac7c
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ public static void Log10<T>(System.ReadOnlySpan<T> x, System.Span<T> destination
public static T MaxMagnitude<T>(System.ReadOnlySpan<T> x) where T : System.Numerics.INumberBase<T> { throw null; }
public static void MaxMagnitude<T>(System.ReadOnlySpan<T> x, System.ReadOnlySpan<T> y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static void MaxMagnitude<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static T MaxMagnitudeNumber<T>(System.ReadOnlySpan<T> x) where T : System.Numerics.INumberBase<T> { throw null; }
public static void MaxMagnitudeNumber<T>(System.ReadOnlySpan<T> x, System.ReadOnlySpan<T> y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static void MaxMagnitudeNumber<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static T Max<T>(System.ReadOnlySpan<T> x) where T : System.Numerics.INumber<T> { throw null; }
public static void Max<T>(System.ReadOnlySpan<T> x, System.ReadOnlySpan<T> y, System.Span<T> destination) where T : System.Numerics.INumber<T> { }
public static void Max<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> destination) where T : System.Numerics.INumber<T> { }
Expand All @@ -485,6 +488,9 @@ public static void MaxNumber<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> de
public static T MinMagnitude<T>(System.ReadOnlySpan<T> x) where T : System.Numerics.INumberBase<T> { throw null; }
public static void MinMagnitude<T>(System.ReadOnlySpan<T> x, System.ReadOnlySpan<T> y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static void MinMagnitude<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static T MinMagnitudeNumber<T>(System.ReadOnlySpan<T> x) where T : System.Numerics.INumberBase<T> { throw null; }
public static void MinMagnitudeNumber<T>(System.ReadOnlySpan<T> x, System.ReadOnlySpan<T> y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static void MinMagnitudeNumber<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> destination) where T : System.Numerics.INumberBase<T> { }
public static T Min<T>(System.ReadOnlySpan<T> x) where T : System.Numerics.INumber<T> { throw null; }
public static void Min<T>(System.ReadOnlySpan<T> x, System.ReadOnlySpan<T> y, System.Span<T> destination) where T : System.Numerics.INumber<T> { }
public static void Min<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> destination) where T : System.Numerics.INumber<T> { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,75 @@ namespace System.Numerics.Tensors
{
public static partial class TensorPrimitives
{
/// <summary>Searches for the number with the largest magnitude in the specified tensor.</summary>
/// <param name="x">The tensor, represented as a span.</param>
/// <returns>The element in <paramref name="x"/> with the largest magnitude (absolute value).</returns>
/// <exception cref="ArgumentException">Length of <paramref name="x" /> must be greater than zero.</exception>
/// <remarks>
/// <para>
/// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitudeNumber` function.
/// If two values have the same magnitude and one is positive and the other is negative,
/// the positive value is considered to have the larger magnitude.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
public static T MaxMagnitudeNumber<T>(ReadOnlySpan<T> x)
where T : INumberBase<T> =>
MinMaxCore<T, MaxMagnitudeNumberOperator<T>>(x);

/// <summary>Computes the element-wise number with the largest magnitude in the specified tensors.</summary>
/// <param name="x">The first tensor, represented as a span.</param>
/// <param name="y">The second tensor, represented as a span.</param>
/// <param name="destination">The destination tensor, represented as a span.</param>
/// <exception cref="ArgumentException">Length of <paramref name="x" /> must be same as length of <paramref name="y" />.</exception>
/// <exception cref="ArgumentException">Destination is too short.</exception>
/// <exception cref="ArgumentException"><paramref name="x"/> and <paramref name="destination"/> reference overlapping memory locations and do not begin at the same location.</exception>
/// <exception cref="ArgumentException"><paramref name="y"/> and <paramref name="destination"/> reference overlapping memory locations and do not begin at the same location.</exception>
/// <remarks>
/// <para>
/// This method effectively computes <c><paramref name="destination" />[i] = <typeparamref name="T"/>.MaxMagnitudeNumber(<paramref name="x" />[i], <paramref name="y" />[i])</c>.
/// </para>
/// <para>
/// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitudeNumber` function.
/// If the two values have the same magnitude and one is positive and the other is negative,
/// the positive value is considered to have the larger magnitude.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
public static void MaxMagnitudeNumber<T>(ReadOnlySpan<T> x, ReadOnlySpan<T> y, Span<T> destination)
where T : INumberBase<T> =>
InvokeSpanSpanIntoSpan<T, MaxMagnitudeNumberOperator<T>>(x, y, destination);

/// <summary>Computes the element-wise number with the largest magnitude in the specified tensors.</summary>
/// <param name="x">The first tensor, represented as a span.</param>
/// <param name="y">The second tensor, represented as a scalar.</param>
/// <param name="destination">The destination tensor, represented as a span.</param>
/// <exception cref="ArgumentException">Destination is too short.</exception>
/// <exception cref="ArgumentException"><paramref name="x"/> and <paramref name="destination"/> reference overlapping memory locations and do not begin at the same location.</exception>
/// <remarks>
/// <para>
/// This method effectively computes <c><paramref name="destination" />[i] = <typeparamref name="T"/>.MaxMagnitudeNumber(<paramref name="x" />[i], <paramref name="y" />)</c>.
/// </para>
/// <para>
/// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitudeNumber` function.
/// If the two values have the same magnitude and one is positive and the other is negative,
/// the positive value is considered to have the larger magnitude.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
public static void MaxMagnitudeNumber<T>(ReadOnlySpan<T> x, T y, Span<T> destination)
where T : INumberBase<T> =>
InvokeSpanScalarIntoSpan<T, MaxMagnitudeNumberOperator<T>>(x, y, destination);

/// <summary>Operator to get x or y based on which has the larger MathF.Abs</summary>
internal readonly struct MaxMagnitudeNumberOperator<T> : IAggregationOperator<T>
where T : INumberBase<T>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,75 @@ namespace System.Numerics.Tensors
{
public static partial class TensorPrimitives
{
/// <summary>Searches for the number with the smallest magnitude in the specified tensor.</summary>
/// <param name="x">The tensor, represented as a span.</param>
/// <returns>The element in <paramref name="x"/> with the smallest magnitude (absolute value).</returns>
/// <exception cref="ArgumentException">Length of <paramref name="x" /> must be greater than zero.</exception>
/// <remarks>
/// <para>
/// The determination of the minimum magnitude matches the IEEE 754:2019 `minimumMagnitudeNumber` function.
/// If two values have the same magnitude and one is positive and the other is negative,
/// the negative value is considered to have the smaller magnitude.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
public static T MinMagnitudeNumber<T>(ReadOnlySpan<T> x)
where T : INumberBase<T> =>
MinMaxCore<T, MinMagnitudeNumberOperator<T>>(x);

/// <summary>Computes the element-wise number with the smallest magnitude in the specified tensors.</summary>
/// <param name="x">The first tensor, represented as a span.</param>
/// <param name="y">The second tensor, represented as a span.</param>
/// <param name="destination">The destination tensor, represented as a span.</param>
/// <exception cref="ArgumentException">Length of <paramref name="x" /> must be same as length of <paramref name="y" />.</exception>
/// <exception cref="ArgumentException">Destination is too short.</exception>
/// <exception cref="ArgumentException"><paramref name="x"/> and <paramref name="destination"/> reference overlapping memory locations and do not begin at the same location.</exception>
/// <exception cref="ArgumentException"><paramref name="y"/> and <paramref name="destination"/> reference overlapping memory locations and do not begin at the same location.</exception>
/// <remarks>
/// <para>
/// This method effectively computes <c><paramref name="destination" />[i] = <typeparamref name="T"/>.MinMagnitudeNumber(<paramref name="x" />[i], <paramref name="y" />[i])</c>.
/// </para>
/// <para>
/// The determination of the maximum magnitude matches the IEEE 754:2019 `minimumMagnitudeNumber` function.
/// If the two values have the same magnitude and one is positive and the other is negative,
/// the negative value is considered to have the smaller magnitude.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
public static void MinMagnitudeNumber<T>(ReadOnlySpan<T> x, ReadOnlySpan<T> y, Span<T> destination)
where T : INumberBase<T> =>
InvokeSpanSpanIntoSpan<T, MinMagnitudeNumberOperator<T>>(x, y, destination);

/// <summary>Computes the element-wise number with the smallest magnitude in the specified tensors.</summary>
/// <param name="x">The first tensor, represented as a span.</param>
/// <param name="y">The second tensor, represented as a scalar.</param>
/// <param name="destination">The destination tensor, represented as a span.</param>
/// <exception cref="ArgumentException">Destination is too short.</exception>
/// <exception cref="ArgumentException"><paramref name="x"/> and <paramref name="destination"/> reference overlapping memory locations and do not begin at the same location.</exception>
/// <remarks>
/// <para>
/// This method effectively computes <c><paramref name="destination" />[i] = <typeparamref name="T"/>.MinMagnitudeNumber(<paramref name="x" />[i], <paramref name="y" />)</c>.
/// </para>
/// <para>
/// The determination of the maximum magnitude matches the IEEE 754:2019 `minimumMagnitudeNumber` function.
/// If the two values have the same magnitude and one is positive and the other is negative,
/// the negative value is considered to have the smaller magnitude.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
public static void MinMagnitudeNumber<T>(ReadOnlySpan<T> x, T y, Span<T> destination)
where T : INumberBase<T> =>
InvokeSpanScalarIntoSpan<T, MinMagnitudeNumberOperator<T>>(x, y, destination);

/// <summary>Operator to get x or y based on which has the smaller MathF.Abs</summary>
internal readonly struct MinMagnitudeNumberOperator<T> : IAggregationOperator<T>
where T : INumberBase<T>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,14 @@ public static IEnumerable<object[]> 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.Max, T.Max);
yield return Create(TensorPrimitives.MaxNumber, T.MaxNumber);
yield return Create(TensorPrimitives.MaxMagnitude, T.MaxMagnitude);
yield return Create(TensorPrimitives.MaxMagnitudeNumber, T.MaxMagnitudeNumber);
yield return Create(TensorPrimitives.Min, T.Min);
yield return Create(TensorPrimitives.MinNumber, T.MinNumber);
yield return Create(TensorPrimitives.MinMagnitude, T.MinMagnitude);
yield return Create(TensorPrimitives.MinMagnitudeNumber, T.MinMagnitudeNumber);
yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance<T>(doubleTolerance: 1e-13, floatTolerance: 1e-5f));

static object[] Create(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func<T, T, T> expectedMethod, T? tolerance = null)
Expand Down Expand Up @@ -656,11 +662,13 @@ public static IEnumerable<object[]> SpanScalarDestinationFunctionsToTest()
yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance<T>(doubleTolerance: 1e-13, floatTolerance: 1e-5f));
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.MaxMagnitude, T.MaxMagnitude);
yield return Create(TensorPrimitives.MaxMagnitudeNumber, T.MaxMagnitudeNumber);
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.MinMagnitude, T.MinMagnitude);
yield return Create(TensorPrimitives.MinMagnitudeNumber, T.MinMagnitudeNumber);

static object[] Create(SpanScalarDestinationDelegate<T, T, T> tensorPrimitivesMethod, Func<T, T, T> expectedMethod, T? tolerance = null)
=> new object[] { tensorPrimitivesMethod, expectedMethod, tolerance };
Expand Down Expand Up @@ -1841,11 +1849,13 @@ public static IEnumerable<object[]> SpanScalarDestinationFunctionsToTest()
yield return Create(TensorPrimitives.BitwiseAnd, (x, y) => x & y);
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.MaxMagnitude, T.MaxMagnitude);
yield return Create(TensorPrimitives.MaxMagnitudeNumber, T.MaxMagnitudeNumber);
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.MinMagnitude, T.MinMagnitude);
yield return Create(TensorPrimitives.MinMagnitudeNumber, T.MinMagnitudeNumber);
yield return Create(TensorPrimitives.Xor, (x, y) => x ^ y);

static object[] Create(SpanScalarDestinationDelegate<T, T, T> tensorPrimitivesMethod, Func<T, T, T> expectedMethod)
Expand Down

0 comments on commit d40ac7c

Please sign in to comment.