Skip to content

Commit

Permalink
Fixes from API review approvals (#104990)
Browse files Browse the repository at this point in the history
* fixes from API review approvals

* API review 2 merged
  • Loading branch information
michaelgsharp authored Jul 19, 2024
1 parent 41e02e5 commit d74d22f
Show file tree
Hide file tree
Showing 6 changed files with 5,062 additions and 1,902 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace System.Numerics.Tensors
{
Expand All @@ -28,9 +29,11 @@ public interface IReadOnlyTensor<TSelf, T> : IEnumerable<T>
void CopyTo(scoped TensorSpan<T> destination);
void FlattenTo(scoped Span<T> destination);

// These are not properties so that structs can implement the interface without allocating:
void GetLengths(scoped Span<nint> destination);
void GetStrides(scoped Span<nint> destination);
[UnscopedRef]
ReadOnlySpan<nint> Lengths { get; }

[UnscopedRef]
ReadOnlySpan<nint> Strides { get; }

ref readonly T GetPinnableReference();
TSelf Slice(params scoped ReadOnlySpan<nint> start);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ public static Tensor<T> Create<T>(scoped ReadOnlySpan<nint> lengths, scoped Read
/// </summary>
/// <param name="values">An array of the backing memory.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
/// <param name="pinned">A <see cref="bool"/> indicating whether the <paramref name="values"/> were pinned or not.</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static Tensor<T> Create<T>(T[] values, scoped ReadOnlySpan<nint> lengths)
=> Create(values, lengths, []);
public static Tensor<T> Create<T>(T[] values, scoped ReadOnlySpan<nint> lengths, bool pinned = false)
=> Create(values, lengths, [], pinned);

/// <summary>
/// Creates a <see cref="Tensor{T}"/> from the provided <paramref name="values"/>. If the product of the
Expand All @@ -55,80 +56,103 @@ public static Tensor<T> Create<T>(T[] values, scoped ReadOnlySpan<nint> lengths)
/// <param name="values">An array of the backing memory.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
/// <param name="strides">A <see cref="ReadOnlySpan{T}"/> indicating the strides of each dimension.</param>
/// <param name="isPinned">A <see cref="bool"/> indicating whether the <paramref name="values"/> were pinned or not.</param>
/// <param name="pinned">A <see cref="bool"/> indicating whether the <paramref name="values"/> were pinned or not.</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static Tensor<T> Create<T>(T[] values, scoped ReadOnlySpan<nint> lengths, scoped ReadOnlySpan<nint> strides, bool isPinned = false)
public static Tensor<T> Create<T>(T[] values, scoped ReadOnlySpan<nint> lengths, scoped ReadOnlySpan<nint> strides, bool pinned = false)
{
return new Tensor<T>(values, lengths, strides, isPinned);
return new Tensor<T>(values, lengths, strides, pinned);
}

/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with the data from <paramref name="data"/>.
/// Creates a <see cref="Tensor{T}"/> and initializes it with the data from <paramref name="values"/>.
/// </summary>
/// <param name="data">A <see cref="IEnumerable{T}"/> with the data to use for the initialization.</param>
/// <param name="lengths"></param>
public static Tensor<T> Create<T>(IEnumerable<T> data, scoped ReadOnlySpan<nint> lengths)
/// <param name="values">A <see cref="IEnumerable{T}"/> with the data to use for the initialization.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
/// <param name="pinned">A <see cref="bool"/> indicating whether the <paramref name="values"/> were pinned or not.</param>

public static Tensor<T> Create<T>(IEnumerable<T> values, scoped ReadOnlySpan<nint> lengths, bool pinned = false)
{
T[] values = data.ToArray();
return new Tensor<T>(values, lengths.IsEmpty ? [values.Length] : lengths, false);
T[] data = values.ToArray();
return new Tensor<T>(data, lengths.IsEmpty ? [data.Length] : lengths, pinned);
}

/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with the data from <paramref name="data"/>.
/// Creates a <see cref="Tensor{T}"/> and initializes it with the data from <paramref name="values"/>.
/// </summary>
/// <param name="data">A <see cref="IEnumerable{T}"/> with the data to use for the initialization.</param>
/// <param name="lengths"></param>
/// <param name="strides"></param>
/// <param name="isPinned"></param>
public static Tensor<T> Create<T>(IEnumerable<T> data, scoped ReadOnlySpan<nint> lengths, scoped ReadOnlySpan<nint> strides, bool isPinned = false)
/// <param name="values">A <see cref="IEnumerable{T}"/> with the data to use for the initialization.</param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
/// <param name="strides">A <see cref="ReadOnlySpan{T}"/> indicating the strides of each dimension.</param>
/// <param name="pinned">A <see cref="bool"/> indicating whether the <paramref name="values"/> were pinned or not.</param>
public static Tensor<T> Create<T>(IEnumerable<T> values, scoped ReadOnlySpan<nint> lengths, scoped ReadOnlySpan<nint> strides, bool pinned = false)
{
T[] values = data.ToArray();
return new Tensor<T>(values, lengths.IsEmpty ? [values.Length] : lengths, strides, isPinned);
T[] data = values.ToArray();
return new Tensor<T>(data, lengths.IsEmpty ? [data.Length] : lengths, strides, pinned);
}

#region Normal
/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with random data uniformly distributed.
/// Creates a <see cref="Tensor{T}"/> and initializes it with random data in a gaussian normal distribution.
/// </summary>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
public static Tensor<T> CreateAndFillUniformDistribution<T>(params scoped ReadOnlySpan<nint> lengths)
public static Tensor<T> CreateAndFillGaussianNormalDistribution<T>(params scoped ReadOnlySpan<nint> lengths)
where T : IFloatingPoint<T>
{
nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths);
T[] values = new T[linearLength];
Random rand = Random.Shared;
for (int i = 0; i < values.Length; i++)
values[i] = T.CreateChecked(rand.NextDouble());

return new Tensor<T>(values, lengths, false);
return CreateAndFillGaussianNormalDistribution<T>(Random.Shared, lengths);
}

#region Normal
/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with random data in a gaussian normal distribution.
/// </summary>
/// <param name="random"></param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
public static Tensor<T> CreateAndFillGaussianNormalDistribution<T>(params scoped ReadOnlySpan<nint> lengths)
public static Tensor<T> CreateAndFillGaussianNormalDistribution<T>(Random random, params scoped ReadOnlySpan<nint> lengths)
where T : IFloatingPoint<T>
{
nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths);
T[] values = new T[linearLength];
GaussianDistribution<T>(values, linearLength);
GaussianDistribution<T>(values, linearLength, random);
return new Tensor<T>(values, lengths, false);
}

private static void GaussianDistribution<T>(in Span<T> values, nint linearLength)
private static void GaussianDistribution<T>(in Span<T> values, nint linearLength, Random random)
where T : IFloatingPoint<T>
{
Random rand = Random.Shared;
for (int i = 0; i < linearLength; i++)
{
double u1 = 1.0 - rand.NextDouble();
double u2 = 1.0 - rand.NextDouble();
double u1 = 1.0 - random.NextDouble();
double u2 = 1.0 - random.NextDouble();
values[i] = T.CreateChecked(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2));
}
}
#endregion


/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with random data uniformly distributed.
/// </summary>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
public static Tensor<T> CreateAndFillUniformDistribution<T>(params scoped ReadOnlySpan<nint> lengths)
where T : IFloatingPoint<T>
{
return CreateAndFillUniformDistribution<T>(Random.Shared, lengths);
}

/// <summary>
/// Creates a <see cref="Tensor{T}"/> and initializes it with random data uniformly distributed.
/// </summary>
/// <param name="random"></param>
/// <param name="lengths">A <see cref="ReadOnlySpan{T}"/> indicating the lengths of each dimension.</param>
public static Tensor<T> CreateAndFillUniformDistribution<T>(Random random, params scoped ReadOnlySpan<nint> lengths)
where T : IFloatingPoint<T>
{
nint linearLength = TensorSpanHelpers.CalculateTotalLength(lengths);
T[] values = new T[linearLength];
for (int i = 0; i < values.Length; i++)
values[i] = T.CreateChecked(random.NextDouble());

return new Tensor<T>(values, lengths, false);
}

/// <summary>
/// Creates a <see cref="Tensor{T}"/> and does not initialize it. If <paramref name="pinned"/> is true, the memory will be pinned.
/// </summary>
Expand All @@ -150,21 +174,21 @@ public static Tensor<T> CreateUninitialized<T>(scoped ReadOnlySpan<nint> lengths
return new Tensor<T>(values, lengths, strides, pinned);
}

public static ref readonly TensorSpan<T> FillGaussianNormalDistribution<T>(in TensorSpan<T> destination) where T : IFloatingPoint<T>
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);

GaussianDistribution<T>(span, destination._shape._memoryLength);
GaussianDistribution<T>(span, destination._shape._memoryLength, random ?? Random.Shared);

return ref destination;
}

public static ref readonly TensorSpan<T> FillUniformDistribution<T>(in TensorSpan<T> destination) where T : IFloatingPoint<T>
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);

random ??= Random.Shared;
for (int i = 0; i < span.Length; i++)
span[i] = T.CreateChecked(Random.Shared.NextDouble());
span[i] = T.CreateChecked(random.NextDouble());

return ref destination;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ static Tensor<T> ITensor<Tensor<T>, T>.CreateUninitialized(ReadOnlySpan<nint> le
/// Gets the length of each dimension in this <see cref="Tensor{T}"/>.
/// </summary>
/// <value><see cref="ReadOnlySpan{T}"/> with the lengths of each dimension.</value>
void IReadOnlyTensor<Tensor<T>, T>.GetLengths(Span<nint> destination) => _lengths.CopyTo(destination);
ReadOnlySpan<nint> IReadOnlyTensor<Tensor<T>, T>.Lengths => _lengths;


/// <summary>
Expand All @@ -185,7 +185,7 @@ static Tensor<T> ITensor<Tensor<T>, T>.CreateUninitialized(ReadOnlySpan<nint> le
/// Gets the strides of each dimension in this <see cref="Tensor{T}"/>.
/// </summary>
/// <value><see cref="ReadOnlySpan{T}"/> with the strides of each dimension.</value>
void IReadOnlyTensor<Tensor<T>, T>.GetStrides(scoped Span<nint> destination) => _strides.CopyTo(destination);
ReadOnlySpan<nint> IReadOnlyTensor<Tensor<T>, T>.Strides => _strides;

bool ITensor<Tensor<T>, T>.IsReadOnly => false;

Expand Down Expand Up @@ -652,10 +652,12 @@ private string ToMetadataString()
/// <returns>A <see cref="string"/> representation of the <see cref="Tensor{T}"/></returns>
public string ToString(params ReadOnlySpan<nint> maximumLengths)
{
if (maximumLengths.Length == 0)
maximumLengths = (from number in Enumerable.Range(0, Rank) select (nint)5).ToArray();
var sb = new StringBuilder();
sb.AppendLine(ToMetadataString());
sb.AppendLine("{");
sb.Append(AsTensorSpan().ToString(10, 10));
sb.Append(AsTensorSpan().ToString(maximumLengths));
sb.AppendLine("}");
return sb.ToString();
}
Expand Down
Loading

0 comments on commit d74d22f

Please sign in to comment.