Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added all missing xml docs for Tensors #106084

Merged
merged 5 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@
<data name="ThrowArgument_SetSliceNoRange" xml:space="preserve">
<value>When no ranges are specified the values tensor must be equal in size as the input tensor.</value>
</data>
<data name="ThrowArgument_ShapesNotBroadcastCompatible" xml:space="preserve">
<value>Shapes are not broadcast compatible.</value>
<data name="ThrowArgument_LengthsNotBroadcastCompatible" xml:space="preserve">
<value>Lengths are not broadcast compatible.</value>
</data>
<data name="ThrowArgument_SplitNotSplitEvenly" xml:space="preserve">
<value>The number of splits must perfectly divide the dimension.</value>
Expand Down Expand Up @@ -228,4 +228,4 @@
<data name="ThrowArgument_StackShapesNotSame" xml:space="preserve">
<value>All tensors must have the same shape.</value>
</data>
</root>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ApiCompatValidateAssemblies>true</ApiCompatValidateAssemblies>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
<!-- SYSLIB5001: Tensor<T> and related APIs in System.Numerics.Tensors are experimental in .NET 9 -->
<NoWarn>$(NoWarn);SYSLIB5001</NoWarn>
<UseCompilerGeneratedDocXmlFile>true</UseCompilerGeneratedDocXmlFile>
</PropertyGroup>

<ItemGroup>
Expand Down
9 changes: 9 additions & 0 deletions src/libraries/System.Numerics.Tensors/src/System/NIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,16 @@ public static NIndex FromEnd(nint value)
return new NIndex(~value);
}

/// <summary>
/// Convert the NIndex to an Index.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <returns>The converted <see cref="Index"/></returns>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
public Index ToIndex() => checked((Index)this);

/// <summary>
/// Convert the NIndex to an Index without doing bounds checks.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <returns>The converted <see cref="Index"/></returns>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
public Index ToIndexUnchecked() => (Index)this;

/// <summary>Returns the NIndex value.</summary>
Expand Down
22 changes: 22 additions & 0 deletions src/libraries/System.Numerics.Tensors/src/System/NRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,34 @@ public override string ToString()

private static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException("length");

/// <summary>
/// Implicitly converts a <see cref="Range"/> to an <see cref="NRange"/>.
/// </summary>
/// <param name="range"></param>
public static implicit operator NRange(Range range) => new NRange(range.Start, range.End);

/// <summary>
/// Explicitly converts an <see cref="NRange"/> to a <see cref="Range"/>.
/// </summary>
/// <param name="value"></param>
public static explicit operator Range(NRange value) => new Range((Index)value.Start, (Index)value.End);

/// <summary>
/// Explicitly converts an <see cref="NRange"/> to a <see cref="Range"/>.
/// </summary>
/// <param name="value"></param>
public static explicit operator checked Range(NRange value) => new Range(checked((Index)value.Start), checked((Index)value.End));

/// <summary>
/// Converts a <see cref="NRange"/> to a <see cref="Range"/>.
/// </summary>
/// <returns>The converted <see cref="Range"/></returns>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
public Range ToRange() => new Range(checked((Index)Start), checked((Index)End));

/// <summary>
/// Converts a <see cref="NRange"/> to a <see cref="Range"/> wihout doing bounds checks.
/// </summary>
/// <returns>The converted <see cref="Range"/></returns>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
public Range ToRangeUnchecked() => new Range((Index)Start, (Index)End);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,148 @@

namespace System.Numerics.Tensors
{
/// <summary>
/// Represents a read-only tensor.
/// </summary>
/// <typeparam name="TSelf">The type that implements this interface.</typeparam>
/// <typeparam name="T">The element type.</typeparam>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public interface IReadOnlyTensor<TSelf, T> : IEnumerable<T>
where TSelf : IReadOnlyTensor<TSelf, T>
{
/// <summary>
/// Gets an empty tensor.
/// </summary>
static abstract TSelf? Empty { get; }

/// <summary>
/// Gets whether the collection is currently empty.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
bool IsEmpty { get; }

/// <summary>
/// Gets whether the underlying buffer pinned.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
bool IsPinned { get; }

/// <summary>
/// Gets the number of elements in the tensor.
/// </summary>
nint FlattenedLength { get; }

/// <summary>
/// Gets the number of dimensions in the tensor.
/// </summary>
int Rank { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to be used.</param>
T this[params scoped ReadOnlySpan<nint> indexes] { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to be used.</param>
T this[params scoped ReadOnlySpan<NIndex> indexes] { get; }

/// <summary>
/// Gets the values at the specified ranges.
/// </summary>
/// <param name="ranges">The ranges to be used.</param>
TSelf this[params scoped ReadOnlySpan<NRange> ranges] { get; }

/// <summary>
/// Creates a read-only tensor span for the entire underlying buffer.
/// </summary>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan();

/// <summary>
/// Creates a read-only tensor span for the specified start indexes.
/// </summary>
/// <param name="start">The start locations to be used.</param>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<nint> start);

/// <summary>
/// Creates a read-only tensor span for the specified start indexes.
/// </summary>
/// <param name="startIndex">The started indexes to be used.</param>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<NIndex> startIndex);

/// <summary>
/// Creates a read-only tensor span for the specified ranges.
/// </summary>
/// <param name="range">The ranges to be used.</param>
/// <returns>The converted <see cref="ReadOnlyTensorSpan{T}"/>.</returns>
ReadOnlyTensorSpan<T> AsReadOnlyTensorSpan(params scoped ReadOnlySpan<NRange> range);

/// <summary>
/// Copies the tensor to the specified destination. The destination tensor must be equal to or larger than the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be copied to.</param>
void CopyTo(scoped TensorSpan<T> destination);

/// <summary>
/// Flattens the tensor to the specified destination. The destination span must be equal to or larger than the number of elements in the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be flattened to.</param>
void FlattenTo(scoped Span<T> destination);

/// <summary>
/// Gets the length of each dimension in the tensor.
/// </summary>
[UnscopedRef]
ReadOnlySpan<nint> Lengths { get; }

/// <summary>
/// Gets the stride of each dimension in the tensor.
/// </summary>
[UnscopedRef]
ReadOnlySpan<nint> Strides { get; }

/// <summary>
/// Returns a reference to the 0th element of the tensor. If the tensor is empty, returns null reference.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// It can be used for pinning and is required to support the use of the tensor within a fixed statement.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
ref readonly T GetPinnableReference();

/// <summary>
/// Slices the tensor using the specified start indexes.
/// </summary>
/// <param name="start">The start locations to be used.</param>
/// <returns>The sliced tensor.</returns>
TSelf Slice(params scoped ReadOnlySpan<nint> start);

/// <summary>
/// Slices the tensor using the specified start indexes.
/// </summary>
/// <param name="startIndex">The start indexes to be used.</param>
/// <returns>The sliced tensor.</returns>
TSelf Slice(params scoped ReadOnlySpan<NIndex> startIndex);

/// <summary>
/// Slices the tensor using the specified ranges.
/// </summary>
/// <param name="range">The ranges to be used.</param>
/// <returns>The sliced tensor.</returns>
TSelf Slice(params scoped ReadOnlySpan<NRange> range);

/// <summary>
/// Tries to copy the tensor to the specified destination. The destination tensor must be equal to or larger than the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be copied to.</param>
/// <returns>True if the copy succeeded, false otherwise.</returns>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
bool TryCopyTo(scoped TensorSpan<T> destination);

/// <summary>
/// Tries to flatten the tensor to the specified destination. The destination span must be equal to or larger than the number of elements in the source tensor.
/// </summary>
/// <param name="destination">The destination span where the data should be flattened to.</param>
/// <returns>True if the copy succeeded, false otherwise.</returns>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
bool TryFlattenTo(scoped Span<T> destination);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

namespace System.Numerics.Tensors
{
/// <summary>
/// Represents a tensor.
/// </summary>
/// <typeparam name="TSelf">The type that implements this interface.</typeparam>
/// <typeparam name="T">The element type.</typeparam>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public interface ITensor<TSelf, T>
: IReadOnlyTensor<TSelf, T>
Expand All @@ -15,25 +20,104 @@ public interface ITensor<TSelf, T>
// It looks like C#/.NET currently hits limitations here as it believes TSelf and T could be the same type
// Ideally we could annotate it such that they cannot be the same type and no conflicts would exist

/// <summary>
/// Creates a new tensor with the specified lengths. If <paramref name="pinned"/> is true the underlying buffer is
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// created permanently pinned, otherwise the underlying buffer is not pinned. The underlying buffer is initialized to default values.
/// </summary>
/// <param name="lengths">The lengths of each dimension.</param>
/// <param name="pinned">Whether the underlying buffer should be pinned or not. Defaults to False.</param>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
static abstract TSelf Create(scoped ReadOnlySpan<nint> lengths, bool pinned = false);

/// <summary>
/// Creates a new tensor with the specified lengths and strides. If <paramref name="pinned"/> is true the underlying buffer is
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// created permanently pinned, otherwise the underlying buffer is not pinned. The underlying buffer is initialized to default values.
/// </summary>
/// <param name="lengths">The lengths of each dimension.</param>
/// <param name="strides">The strides of each dimension.</param>
/// <param name="pinned">Whether the underlying buffer should be pinned or not. Defaults to False.</param>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
static abstract TSelf Create(scoped ReadOnlySpan<nint> lengths, scoped ReadOnlySpan<nint> strides, bool pinned = false);

/// <summary>
/// Creates a new tensor with the specified lengths and strides. If <paramref name="pinned"/> is true the underlying buffer is
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// created permanently pinned, otherwise the underlying buffer is not pinned. The underlying buffer is not initialized.
/// </summary>
/// <param name="lengths">The lengths of each dimension.</param>
/// <param name="pinned">Whether the underlying buffer should be pinned or not. Defaults to False.</param>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
static abstract TSelf CreateUninitialized(scoped ReadOnlySpan<nint> lengths, bool pinned = false);

/// <summary>
/// Creates a new tensor with the specified lengths and strides. If <paramref name="pinned"/> is true the underlying buffer is
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// created permanently pinned, otherwise the underlying buffer is not pinned. The underlying buffer is not initialized.
/// </summary>
/// <param name="lengths">The lengths of each dimension.</param>
/// <param name="strides">The strides of each dimension.</param>
/// <param name="pinned">Whether the underlying buffer should be pinned or not. Defaults to False.</param>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
static abstract TSelf CreateUninitialized(scoped ReadOnlySpan<nint> lengths, scoped ReadOnlySpan<nint> strides, bool pinned = false);

/// <summary>
/// Gets whether the collection is read-only.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
bool IsReadOnly { get; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to use.</param>
new T this[params scoped ReadOnlySpan<nint> indexes] { get; set; }

/// <summary>
/// Gets the value at the specified indexes.
/// </summary>
/// <param name="indexes">The indexes to use.</param>
new T this[params scoped ReadOnlySpan<NIndex> indexes] { get; set; }

/// <summary>
/// Gets the values at the specified ranges.
/// </summary>
/// <param name="ranges">The ranges to be used.</param>
new TSelf this[params scoped ReadOnlySpan<NRange> ranges] { get; set; }

/// <summary>
/// Creates a tensor span for the entire underlying buffer.
/// </summary>
/// <returns>The converted <see cref="TensorSpan{T}"/>.</returns>
TensorSpan<T> AsTensorSpan();

/// <summary>
/// Creates a tensor span for the specified start indexes.
/// </summary>
/// <param name="start">The start locations to be used.</param>
/// <returns>The converted <see cref="TensorSpan{T}"/>.</returns>
TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<nint> start);

/// <summary>
/// Creates a tensor span for the specified start indexes.
/// </summary>
/// <param name="startIndex">The start indexes to be used.</param>
/// <returns>The converted <see cref="TensorSpan{T}"/>.</returns>
TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<NIndex> startIndex);

/// <summary>
/// Creates a tensor span for the specified ranges.
/// </summary>
/// <param name="range">The ranges to be used.</param>
/// <returns>The converted <see cref="TensorSpan{T}"/>.</returns>
TensorSpan<T> AsTensorSpan(params scoped ReadOnlySpan<NRange> range);

/// <summary>
/// Clears the tensor.
/// </summary>
void Clear();

/// <summary>
/// Fills the contents of this tensor with the given value.
/// </summary>
void Fill(T value);

/// <summary>
/// Returns a reference to the 0th element of the tensor. If the tensor is empty, returns null reference.
/// It can be used for pinning and is required to support the use of the tensor within a fixed statement.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
new ref T GetPinnableReference();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,9 @@ public bool TryCopyTo(scoped TensorSpan<T> destination)
return retVal;
}

//public static explicit operator TensorSpan<T>(Array? array);
/// <summary>
/// Defines an implicit conversion of an array to a <see cref="TensorSpan{T}"/>.
/// </summary>
public static implicit operator ReadOnlyTensorSpan<T>(T[]? array) => new ReadOnlyTensorSpan<T>(array);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

namespace System.Numerics.Tensors
{
/// <summary>
/// Static class that contains methods for creating tensors.
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public static partial class Tensor
{
/// <summary>
Expand Down Expand Up @@ -175,6 +178,14 @@ public static Tensor<T> CreateUninitialized<T>(scoped ReadOnlySpan<nint> lengths
return new Tensor<T>(values, lengths, strides, pinned);
}

/// <summary>
/// Fills the given <see cref="TensorSpan{T}"/> with random data in a gaussian normal distribution. <see cref="System.Random"/>
michaelgsharp marked this conversation as resolved.
Show resolved Hide resolved
/// can optionally be provided for seeding.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="destination">The destination <see cref="TensorSpan{T}"/> where the data will be stored.</param>
/// <param name="random"><see cref="System.Random"/> to provide random seeding. Defaults to <see cref="Random.Shared"/> if not provided.</param>
/// <returns></returns>
public static ref readonly TensorSpan<T> FillGaussianNormalDistribution<T>(in TensorSpan<T> destination, Random? random = null) where T : IFloatingPoint<T>
{
Span<T> span = MemoryMarshal.CreateSpan<T>(ref destination._reference, (int)destination._shape._memoryLength);
Expand All @@ -184,6 +195,14 @@ public static ref readonly TensorSpan<T> FillGaussianNormalDistribution<T>(in Te
return ref destination;
}

/// <summary>
/// Fills the given <see cref="TensorSpan{T}"/> with random data in a uniform distribution. <see cref="System.Random"/>
/// can optionally be provided for seeding.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="destination">The destination <see cref="TensorSpan{T}"/> where the data will be stored.</param>
/// <param name="random"><see cref="System.Random"/> to provide random seeding. Defaults to <see cref="Random.Shared"/> if not provided.</param>
/// <returns></returns>
public static ref readonly TensorSpan<T> FillUniformDistribution<T>(in TensorSpan<T> destination, Random? random = null) where T : IFloatingPoint<T>
{
Span<T> span = MemoryMarshal.CreateSpan<T>(ref destination._reference, (int)destination._shape._memoryLength);
Expand Down
Loading
Loading