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

Use SIMD to accelerate operations #34

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
110 changes: 110 additions & 0 deletions docs/articles/Interfaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Exploring Geometric Interfaces in C# with NetFabric.Numerics

If you're a C# developer interested in working with geometric types and coordinate systems, the `NetFabric.Numerics` package offers a powerful set of interfaces and data structures. In this article, we'll take a deep dive into the core interfaces provided by the package and explore how they can help you model geometric data efficiently.

## ICoordinateSystem Interface

Introducing the `ICoordinateSystem` interface, which plays a key role in providing access to coordinate information within a system. Here's the code snippet:

```csharp
public interface ICoordinateSystem
{
IReadOnlyList<Coordinate> Coordinates { get; }
}
```

The `Coordinates` property returns an `IReadOnlyCollection<Coordinate`, ensuring you can access information about each coordinate while maintaining data integrity.

`Coordinate` is defined as follow:

```csharp
public readonly record struct Coordinate(string Name, Type Type);
```

This code defines a read-only struct, `Coordinate`, which holds the name and type for a coordinate. It's useful for dynamic queries of the coordinate system, especially for tasks like serialization and creating user interfaces. These practices align with modern C# coding standards and can enhance code performance and efficiency.

### IGeometricBase

The `IGeometricBase` interface is at the core of the geometric types in the `NetFabric.Numerics` package. It defines a common set of operations and properties for geometric objects. Let's explore the key elements of this interface:

```csharp
public interface IGeometricBase<TSelf, TCoordinateSystem>
: IEquatable<TSelf>,
IEqualityOperators<TSelf, TSelf, bool>
where TSelf : struct, IGeometricBase<TSelf, TCoordinateSystem>?
where TCoordinateSystem : class, ICoordinateSystem
{
TCoordinateSystem CoordinateSystem { get; }

object this[int index] { get; }

static abstract TSelf Zero { get; }

public static bool IsZero(TSelf value)
=> value.Equals(TSelf.Zero);
}
```

The definition implies that all geometric objects must be equatable, emeaning that they mus implement the generics version of `Equals` and also must implement all the equality operators.

They must provide a `CoordinateSystem` property that returns and instance of class (reference type) that implements `ICoordinateSystem`. This allows the dynamic queries in realtime about the coordinate system the geometric object is defined in.

Having it be a reference type and implement the singleton pattern, makes it more efficient to compare if two geometric object are from the same coordinate system. The equal operator will internally use the `ReferenceEquals`.


## Points in Space

### IPoint Interface

Building on the `IGeometricBase` interface, the `IPoint` interface is tailored for representing points in a coordinate system. It includes additional capabilities, such as finding the minimum and maximum values for points. Here's the definition of the `IPoint` interface:

```csharp
namespace NetFabric.Numerics;

public interface IPoint<TSelf, TCoordinateSystem>
: IGeometricBase<TSelf, TCoordinateSystem>,
IMinMaxValue<TSelf>
where TSelf : struct, IPoint<TSelf, TCoordinateSystem>?
where TCoordinateSystem : class, ICoordinateSystem
{
}
```

The `IPoint` interface adds the ability to find the minimum and maximum values for points, which can be particularly useful in spatial applications.

## Vectors in Space

### IVector Interface

Lastly, the `IVector` interface is designed for modeling vectors in a coordinate system. It encompasses a wide range of mathematical operations and comparisons. Here's how it's defined:

```csharp
namespace NetFabric.Numerics;

public interface IVector<TSelf, TCoordinateSystem, T>
: IGeometricBase<TSelf, TCoordinateSystem>,
IComparable,
IComparable<TSelf>,
IComparisonOperators<TSelf, TSelf, bool>,
IAdditiveIdentity<TSelf, TSelf>,
IUnaryPlusOperators<TSelf, TSelf>,
IAdditionOperators<TSelf, TSelf, TSelf>,
IUnaryNegationOperators<TSelf, TSelf>,
ISubtractionOperators<TSelf, TSelf, TSelf>,
IMultiplyOperators<TSelf, T, TSelf>,
IDivisionOperators<TSelf, T, TSelf>,
IMinMaxValue<TSelf>
where TSelf : struct, IVector<TSelf, TCoordinateSystem, T>?
where TCoordinateSystem : class, ICoordinateSystem
where T : struct, INumber<T>, IMinMaxValue<T>
{
}
```

The `IVector` interface is a versatile tool for working with vectors. It supports operations such as addition, subtraction, unary negation, and scalar multiplication, making it an essential foundation for vector mathematics.

## Wrapping Up

The `NetFabric.Numerics` package provides a robust set of interfaces for modeling geometric data and coordinate systems in C#. By adhering to these interfaces and following the coding guidelines you've specified, you can build efficient and maintainable code for geometric calculations. Whether you're working on 2D or 3D graphics, physics simulations, or any other domain involving spatial data, these interfaces are a valuable resource for your C# projects. Happy coding!

*Note: The code snippets provided in this article adhere to the coding guidelines specified, using up-to-date C# syntax and providing well-structured inline documentation where relevant.*
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0; net8.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Title>NetFabric.Numerics.Angle</Title>
<TargetFrameworks>net7.0; net8.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>
A strongly-typed representation of an angle.
Expand Down
45 changes: 9 additions & 36 deletions src/NetFabric.Numerics.Benchmarks/AdditionBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ public class AdditionBenchmarks
Rectangular2D.Vector<long>[]? rectangular2_long;
Rectangular2D.Vector<float>[]? rectangular2_float;
Rectangular2D.Vector<double>[]? rectangular2_double;

Polar.Vector<Degrees, float>[]? polar_float;
Polar.Vector<Degrees, double>[]? polar_double;

[Params(10_000)]
public int Count { get; set; }
Expand All @@ -31,9 +28,6 @@ public void GlobalSetup()
rectangular2_float = GetEnumerable(Count).Select<(int x, int y), Rectangular2D.Vector<float>>(item => new(item.x, item.y)).ToArray();
rectangular2_double = GetEnumerable(Count).Select<(int x, int y), Rectangular2D.Vector<double>>(item => new(item.x, item.y)).ToArray();

polar_float = GetEnumerable(Count).Select<(int x, int y), Polar.Vector<Degrees, float>>(item => new(item.x, new(item.y))).ToArray();
polar_double = GetEnumerable(Count).Select<(int x, int y), Polar.Vector<Degrees, double>>(item => new(item.x, new(item.y))).ToArray();

static IEnumerable<(int x, int y)> GetEnumerable(int count)
{
var random = new Random(42);
Expand Down Expand Up @@ -64,15 +58,15 @@ public Rectangular2D.Vector<long> Rectangular2D_Long()
return sum;
}

[BenchmarkCategory("Float")]
[Benchmark(Baseline = true)]
public Vector2 Vector2()
{
var sum = System.Numerics.Vector2.Zero;
foreach (var item in vector2!)
sum += item;
return sum;
}
// [BenchmarkCategory("Float")]
// [Benchmark(Baseline = true)]
// public Vector2 Vector2()
// {
// var sum = System.Numerics.Vector2.Zero;
// foreach (var item in vector2!)
// sum += item;
// return sum;
// }

[BenchmarkCategory("Float")]
[Benchmark]
Expand All @@ -84,16 +78,6 @@ public Rectangular2D.Vector<float> Rectangular2D_Float()
return sum;
}

[BenchmarkCategory("Float")]
[Benchmark]
public Polar.Vector<Degrees, float> Polar_Float()
{
var sum = Polar.Vector<Degrees, float>.Zero;
foreach (var item in polar_float!)
sum += item;
return sum;
}

[BenchmarkCategory("Double")]
[Benchmark(Baseline = true)]
public Rectangular2D.Vector<double> Rectangular2D_Double()
Expand All @@ -103,15 +87,4 @@ public Rectangular2D.Vector<double> Rectangular2D_Double()
sum += item;
return sum;
}

[BenchmarkCategory("Double")]
[Benchmark]
public Polar.Vector<Degrees, double> Polar_Double()
{
var sum = Polar.Vector<Degrees, double>.Zero;
foreach (var item in polar_double!)
sum += item;
return sum;
}

}
69 changes: 0 additions & 69 deletions src/NetFabric.Numerics.Benchmarks/AdditionVectorDoubleBenchmark.cs

This file was deleted.

113 changes: 0 additions & 113 deletions src/NetFabric.Numerics.Benchmarks/AdditionVectorFloatBenchmark.cs

This file was deleted.

Loading
Loading