From cfb59cb28fc9fc7012324c94fd812e66b2935343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anta=CC=83o=20Almada?= Date: Tue, 6 Feb 2024 21:19:07 +0000 Subject: [PATCH] Improve documentation --- README.md | 2 +- docs/articles/Benchmarks.md | 22 +++++++++++----------- docs/articles/Extending-the-library.md | 26 +++++++++++++++----------- docs/articles/Getting-started.md | 2 +- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index d962667..78959d9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Dealing with SIMD in .NET for optimized code can be complex, but this library offers a practical solution. It provides a reusable and highly-optimized iterations on `Span`, enabling the application of both pre-defined and custom operations to each element. -Using generics, the library accommodates any type embracing [generic math](https://aalmada.github.io/Generic-math-in-dotnet.html). +Using generics, the library accommodates any type embracing [generic math](https://learn.microsoft.com/en-us/dotnet/standard/generics/math). Within the library, you'll find pre-defined operations such as `Sqrt()`, `Sin()`, `Negate()`, `Add()`, `Divide()`, `Multiply()`, `AddMultiply()`, `Sum()`, `Average()`, and many more. diff --git a/docs/articles/Benchmarks.md b/docs/articles/Benchmarks.md index f67baab..8f93b0e 100644 --- a/docs/articles/Benchmarks.md +++ b/docs/articles/Benchmarks.md @@ -13,25 +13,25 @@ AMD Ryzen 9 7940HS w/ Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cor Vector512 : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI ``` -It performs the following bechmarks - -- `Baseline_*` - using a simple iteration without explicit optimizations. -- `LINQ_*` - using LINQ (when available). -- `System_*` - using `System.Numerics.Tensors` (only for `Single`; `float` in C#, or `float32` in F#). -- `NetFabric_*` - using `NetFabric.Numerics.Tensors`. - -Every benchmark encompassed four distinct jobs: +Notice that this sytem supports vectorization up to 512 bits. The benchmarks will be performed without vectorization and for each vectorization size. Every benchmark encompassed four distinct jobs: - `Scalar` - without any SIMD support - `Vector128` - utilizing 128-bit SIMD support - `Vector256` - utilizing 256-bit SIMD support - `Vector512` - utilizing 512-bit SIMD support +It performs the following bechmarks: + +- `Baseline_*` - using a simple iteration without explicit optimizations. +- `LINQ_*` - using LINQ (when available). +- `System_*` - using `System.Numerics.Tensors` (only for `Single`; `float` in C#, or `float32` in F#). +- `NetFabric_*` - using `NetFabric.Numerics.Tensors`. + The full benchmarking source code can be found [here](https://github.com/NetFabric/NetFabric.Numerics.Tensors/tree/main/src/NetFabric.Numerics.Tensors.Benchmarks). -### Add +### Addition -Benchmarks performing addition on two spans (tensors), each containing 1,000 items, +Benchmarks performing addition on two spans, each containing 1,000 items, outputing to another span. The following serves as the baseline against which performance is evaluated: @@ -214,7 +214,7 @@ It additionally compares with the performance of LINQ's `Sum()`. However, it's w ### Sum2D -Benchmarks performing the sum of the 2D vectors in a span (tensor), containing 1,000 vectors. The vector is a value type containing two fields of the same type. +Benchmarks performing the sum of the 2D vectors in a span, containing 1,000 vectors. The vector is a value type containing two fields of the same type. It uses the same baseline as for the `Sum` benchmarks as it uses generics math to support any of these cases. diff --git a/docs/articles/Extending-the-library.md b/docs/articles/Extending-the-library.md index 223cbef..7812b6f 100644 --- a/docs/articles/Extending-the-library.md +++ b/docs/articles/Extending-the-library.md @@ -65,11 +65,13 @@ public interface ITernaryOperator It's essential to note that these interfaces make use of [static virtual members](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/static-virtual-interface-members), a feature introduced in .NET 7. No instance of the operator is required to utilize the methods, and operators are pure, devoid of internal state. -Each operator must implement two methods that define the operation between elements of type `T` or vectors of type `Vector`. Each interface specifies a different number of parameters. -Consider the square operator as an example, which functions as a unary operator designed to operate on a single source. The generic type `T` is restricted to `struct` and must implement `IMultiplyOperators` of values: +Each operator must implement two `Invoke` methods that define the operation between elements of type `T` or vectors of type `Vector`. Each interface specifies a different number of parameters. + +Consider the square operator as an example, which functions as a unary operator designed to operate on a single source. It implements the `IUnaryOperator` interface. The generic type `T` is restricted to `struct` and must implement `IMultiplyOperators` of values: ```csharp -public readonly struct SquareOperator : IUnaryOperator +public readonly struct SquareOperator + : IUnaryOperator where T : struct, IMultiplyOperators { public static T Invoke(T x) @@ -80,10 +82,11 @@ public readonly struct SquareOperator : IUnaryOperator } ``` -Similarly, consider an addition operator, a binary operator that works on two sources, the addends. The generic type `T` is confined to `struct` and must implement `IAdditionOperators`, indicating that only value types with the `+` operator implemented are eligible. The `Invoke` methods straightforwardly perform the addition operation for either a single `T` value or a `Vector` of values: +Similarly, consider an addition operator, a binary operator that works on two sources, the addends. It implements the `IBinaryOperator` interface. The generic type `T` is confined to `struct` and must implement `IAdditionOperators`, indicating that only value types with the `+` operator implemented are eligible. The `Invoke` methods straightforwardly perform the addition operation for either a single `T` value or a `Vector` of values: ```csharp -readonly struct AddOperator : IBinaryOperator +readonly struct AddOperator + : IBinaryOperator where T : struct, IAdditionOperators { public static T Invoke(T x, T y) @@ -94,10 +97,11 @@ readonly struct AddOperator : IBinaryOperator } ``` -Furthermore, consider an operator calculating the addition followed by multiplication of values. This is a ternary operator that handles three sources: the addends plus the multiplier. The generic type `T` is constrained to `struct`, `IAdditionOperators`, and `IMultiplyOperators`, indicating that only value types with the `+` and `*` operators implemented are applicable. The `Invoke` methods straightforwardly perform the addition operation followed by multiplication for either a single `T` value or a `Vector` of values: +Furthermore, consider an operator calculating the addition followed by multiplication of values. This is a ternary operator that handles three sources: the two addends plus the multiplier. it implements the `ITernaryOperator` interface. The generic type `T` is constrained to `struct`, `IAdditionOperators`, and `IMultiplyOperators`, indicating that only value types with the `+` and `*` operators implemented are applicable. The `Invoke` methods straightforwardly perform the addition operation followed by multiplication for either a single `T` value or a `Vector` of values: ```csharp -readonly struct AddMultiplyOperator : ITernaryOperator +readonly struct AddMultiplyOperator + : ITernaryOperator where T : struct, IAdditionOperators, IMultiplyOperators { public static T Invoke(T x, T y, T z) @@ -126,9 +130,9 @@ public interface IAggregationOperator } ``` -Each operator must implement a property that returns the identity value for the operation, which initializes the aggregation process. Additionally, operators must implement the two methods required by the `IBinaryOperator` interface, along with two additional methods that aggregate the final result. +Each operator must implement a property that returns the identity value for the operation, which initializes the aggregation process. Additionally, operators must implement the two `Invoke` methods required by the `IBinaryOperator` interface, along with two additional `Invoke` methods that aggregate the final result. -Consider, for instance, an operator that calculates the sum of all elements in the source. This serves as an aggregation operator, providing a value. The generic type `T` is restricted to `struct`, `IAdditiveIdentity`, and `IAdditionOperators`, signifying that only value types with both the additive identity and the `+` operator implemented are suitable. The `Identity` initializes the sum using the additive identity. The `Invoke` methods handle the addition of `T` and `Vector` values. +Consider, for instance, an operator that calculates the sum of all elements in the source. This serves as an aggregation operator, providing a value. It implements the `IAggregationOperator` interface. The generic type `T` is restricted to `struct`, `IAdditiveIdentity`, and `IAdditionOperators`, signifying that only value types with both the additive identity and the `+` operator implemented are suitable. The `Identity` initializes the sum using the additive identity. The `Invoke` methods handle the addition of `T` and `Vector` values. ```csharp readonly struct SumOperator : IAggregationOperator @@ -148,9 +152,9 @@ readonly struct SumOperator : IAggregationOperator } ``` -## Operators Incompatible with Vectorization +## Operators Unsuitable for Vectorization -It's essential to recognize that specific operators may have partial or no support when it comes to `Vector`. +It's crucial to acknowledge that certain operators may lack full compatibility or support with `Vector`. While alternative optimizations can still be applied, vectorization will have to be disabled for these operations. All operator interfaces inherit from the following interface: diff --git a/docs/articles/Getting-started.md b/docs/articles/Getting-started.md index 52cfa04..4c0d5ef 100644 --- a/docs/articles/Getting-started.md +++ b/docs/articles/Getting-started.md @@ -1,6 +1,6 @@ # Getting Started with NetFabric.Numerics.Tensors -To kick off your exploration of NetFabric.Numerics.Tensors, grab it conveniently from NuGet. Embed it as a dependency in your project, either by executing the command line steps (outlined on the NuGet page) or through your preferred dependency manager. +To kick off your exploration of NetFabric.Numerics.Tensors, grab it from [NuGet](https://www.nuget.org/packages/NetFabric.Numerics.Tensors). Embed it as a dependency in your project, either by executing the command line steps ([outlined on the NuGet page](https://www.nuget.org/packages/NetFabric.Numerics.Tensors)) or through your preferred dependency manager. Import the library into your source code files as needed – include `using NetFabric.Numerics.Tensors;` in your C# files or `open NetFabric.Numerics.Tensors` if you're working in F#.