Skip to content

Commit

Permalink
Merge pull request #9 from HamletTanyavong/dev
Browse files Browse the repository at this point in the history
Remove type parameter requirement for numeric types
  • Loading branch information
HamletTanyavong authored Oct 8, 2023
2 parents 01d55c9 + 59e75bd commit 07cdd16
Show file tree
Hide file tree
Showing 31 changed files with 1,473 additions and 1,130 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
/src/Mathematics.NET.DevApp/*.cs
*.runsettings

# Temporary
/src/Mathematics.NET.SourceGenerators/

# User-specific files
*.rsuser
*.suo
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h1 align="center">Mathematics.NET</h1>
# Mathematics.NET

<p align="center">Mathematics.NET is a C# class library that provides tools for solving mathematical problems.</p>
Mathematics.NET is a C# class library that provides tools for solving mathematical problems.

[![GitHub](https://img.shields.io/github/license/HamletTanyavong/Mathematics.NET?style=flat-square&logo=github&labelColor=87cefa&color=ffd700)](https://github.com/HamletTanyavong/Mathematics.NET)
[![GitHub Repo Stars](https://img.shields.io/github/stars/HamletTanyavong/Mathematics.NET?color=87cefa&style=flat-square&logo=github)](https://github.com/HamletTanyavong/Mathematics.NET/stargazers)
Expand Down
38 changes: 14 additions & 24 deletions docs/articles/fundamentals/numeric-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,57 @@

There are three numeric types that can be used to represent complex, real, and rational numbers in Mathematics.NET.

All Mathematics.NET numbers implement the [IComplex<T, U>](https://mathematics.hamlettanyavong.com/api/Mathematics.NET.Core.IComplex-2.html) interface. Particularly useful is the fact that, unlike .NET runtime's [INumberBase\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs), `IComplex<T, U>` defines the `Conjugate` method; this is incredibly helpful in avoiding code duplication for calculations involving complex and real numbers.
All Mathematics.NET numbers implement the [IComplex\<T\>](https://mathematics.hamlettanyavong.com/api/Mathematics.NET.Core.IComplex-1.html) interface. Particularly useful is the fact that, unlike .NET runtime's [INumberBase\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs), `IComplex<T>` defines the `Conjugate` method; this is helpful in avoiding code duplication for calculations involving complex and real numbers.

## Floating-Point Types

Floating-point Mathematics.NET numbers may be backed any number that implements [IFloatingPointIee754\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs) and [IMinMaxValue\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IMinMaxValue.cs), or more specifically, [float](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Single.cs), [double](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Double.cs), and [decimal](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Decimal.cs).
Floating-point Mathematics.NET numbers are backed by the [double](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Double.cs) numeric type.

### Complex Numbers

To create a complex number, we choose a backing type, in this case `double`, and write
To create a complex number, we can write
```csharp
Complex<double> z = new(3, 4);
ComplexNumber z = new(3, 4);
```
This represents the number $ z = 3+i4 $. We can also specify only one number to create a complex number with no imaginary part
```csharp
Complex<double> z = 3;
ComplexNumber z = 3;
```
which represents $ z = 3 $.

### Real Numbers

Likewise, to create a real number, write
```csharp
Real<double> z = 1;
Real x = 1.23;
```
With real numbers, we can also get maximum and minimum values which will depend on the backing type.
To get is backing value, write
```csharp
Console.WriteLine("Max value with float backing type: {0}", Real<float>.MaxValue);
Console.WriteLine("Max value with double backing type: {0}", Real<double>.MaxValue);
double backingValue = x.Value;
```
This will output `Max value with float backing type: 3.4028235E+38`
and `Max value with double backing type: 1.7976931348623157E+308`.

## Binary Types

Rational numbers are the only Mathematics.NET type in this category.

### Rational Numbers

Rational numbers require two backing types, one that implements [IBinaryInteger\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs) and one that implements both [IFloatingPointIee754\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs) and [IMinMaxValue\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IMinMaxValue.cs).
Rational numbers require a type parameter that implements [IBinaryInteger\<T\>](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs). The type specified here is used to represent the numerator and denominator of the rational number.

With this information, we can create the following rational numbers:
```csharp
Rational<int, double> a = 2;
Rational<byte, float> b = new(2, 3);
Rational<BigInteger, double> c = new(3, 4);
Rational<int> a = 2;
Rational<byte> b = new(2, 3);
Rational<BigInteger> c = new(3, 4);
```
which represent $ a = 2 $, $ b = 2/3 $, and $ c = 3/4 $.

The first type parameter indicates that the constructor only accepts values of that type. In these cases, `a` must be an int, `b` must be a byte, and `c` must be a BigInteger. The second parameter indicates the desired floating-point type with which we want to represent the rational number. We can get this value in two ways, e.g.
```csharp
Console.WriteLine(b.Value);
Console.WriteLine((float)b);
```
which will both output `0.6666667`.

> [!CAUTION]
> The floating-point representation of rational numbers may not be accurate in all cases.
We can also convert a floating-point number into a rational number with an explicit cast
We can also convert a double into a rational number with an explicit cast
```csharp
Console.WriteLine((Rational<int, double>)3.14);
Console.WriteLine((Rational<int>)3.14);
```
> [!NOTE]
> The conversion conversion is not guaranteed to create the "best" fraction; for instance, the value $ 0.3333333333333333 $ will not produce $ 1/3 $ but instead produce $ 8333333333333331 / 25000000000000000 $.
Expand Down
2 changes: 1 addition & 1 deletion docs/articles/get_started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Mathematics.NET is available to download from [nuget](https://www.nuget.org/pack

# [Package Reference](#tab/package-reference)

To use Mathematics.NET in you project, add the following line to your .csproj file:
To use Mathematics.NET in your project, add the following line to your .csproj file:
```xml
<PackageReference Include="Physics.NET.Mathematics" Version="" />
```
Expand Down
1 change: 1 addition & 0 deletions src/Mathematics.NET.DevApp/Mathematics.NET.DevApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<ProjectReference Include="..\Mathematics.NET\Mathematics.NET.csproj" />
<ProjectReference Include="..\Mathematics.NET.SourceGenerators\Mathematics.NET.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
59 changes: 59 additions & 0 deletions src/Mathematics.NET.SourceGenerators/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// <copyright file="Extensions.cs" company="Mathematics.NET">
// Mathematics.NET
// https://github.com/HamletTanyavong/Mathematics.NET
//
// MIT License
//
// Copyright (c) 2023 Hamlet Tanyavong
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// </copyright>

namespace Mathematics.NET.SourceGenerators;

public static class Extensions
{
public static string? GetValue(this NameSyntax name)
{
return name switch
{
SimpleNameSyntax simpleNameSyntax => simpleNameSyntax.Identifier.Text,
QualifiedNameSyntax qualifiedNameSyntax => qualifiedNameSyntax.Right.Identifier.Text,
_ => null
};
}

// TODO: Determine if every equation should/will have an attribute to remove.
public static MethodDeclarationSyntax RemoveEquationAttribute(this MethodDeclarationSyntax methodDeclarationSyntax)
{
var equationAttributeNode = methodDeclarationSyntax
.DescendantNodes()
.OfType<AttributeSyntax>()
.First(syntax => syntax.Name.GetValue() is "Equation" or "EquationAttribute");

if (equationAttributeNode.Parent!.ChildNodes().Count() > 1)
{
return methodDeclarationSyntax.RemoveNode(equationAttributeNode, SyntaxRemoveOptions.KeepNoTrivia)!;
}
else
{
return methodDeclarationSyntax.RemoveNode(equationAttributeNode.Parent, SyntaxRemoveOptions.KeepNoTrivia)!;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// <copyright file="DerivativeGenerator.cs" company="Mathematics.NET">
// Mathematics.NET
// https://github.com/HamletTanyavong/Mathematics.NET
//
// MIT License
//
// Copyright (c) 2023 Hamlet Tanyavong
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// </copyright>

using System.Collections.Immutable;
using System.Text;
using Mathematics.NET.SourceGenerators.Models;
using Mathematics.NET.SourceGenerators.SourceBuilders;

namespace Mathematics.NET.SourceGenerators.IncrementalGenerators;

/// <summary>A generator for calculating derivatives</summary>
[Generator]
public sealed class DerivativeGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context.SyntaxProvider
.CreateSyntaxProvider(CouldBeEquationAttribute, GetEquationOrNull)
.Where(info => info is not null);
var compilation = context.CompilationProvider.Combine(provider.Collect());
context.RegisterSourceOutput(compilation, (context, source) => GenerateCode(context, source.Left, source.Right!));
}

private static bool CouldBeEquationAttribute(SyntaxNode syntaxNode, CancellationToken cancellationToken)
=> syntaxNode is AttributeSyntax attributeSyntax && attributeSyntax.Name.GetValue() is "Equation" or "EquationAttribute";

private static MethodInformation? GetEquationOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken)
{
// The method syntax will not be null if attribute syntax is not null since the attribute can only be applied to methods.
var attribute = (AttributeSyntax)context.Node;
return new(attribute, (MethodDeclarationSyntax)attribute.Parent!.Parent!);
}

private void GenerateCode(SourceProductionContext context, Compilation compilation, ImmutableArray<MethodInformation> methodInformation)
{
var derivatives = new DerivativesBuilder(compilation, methodInformation);
context.AddSource("Equations.g.cs", derivatives.GenerateSource().GetText(Encoding.UTF8).ToString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IncludeBuildOutput>false</IncludeBuildOutput>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TargetFramework>netstandard2.0</TargetFramework>
<Platforms>x64</Platforms>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
42 changes: 42 additions & 0 deletions src/Mathematics.NET.SourceGenerators/Models/MethodInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// <copyright file="MethodInformation.cs" company="Mathematics.NET">
// Mathematics.NET
// https://github.com/HamletTanyavong/Mathematics.NET
//
// MIT License
//
// Copyright (c) 2023 Hamlet Tanyavong
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// </copyright>

namespace Mathematics.NET.SourceGenerators.Models;

/// <summary>A class containing information about a specific method</summary>
public sealed class MethodInformation
{
public MethodInformation(AttributeSyntax attributeSyntax, MethodDeclarationSyntax methodDeclaration)
{
AttributeSyntax = attributeSyntax;
MethodDeclaration = methodDeclaration;
}

public AttributeSyntax AttributeSyntax { get; }

public MethodDeclarationSyntax MethodDeclaration { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// <copyright file="DerivativesBuilder.cs" company="Mathematics.NET">
// Mathematics.NET
// https://github.com/HamletTanyavong/Mathematics.NET
//
// MIT License
//
// Copyright (c) 2023 Hamlet Tanyavong
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// </copyright>

using System.Collections.Immutable;
using Mathematics.NET.SourceGenerators.Models;
using Microsoft.CodeAnalysis.CSharp;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Mathematics.NET.SourceGenerators.SourceBuilders;

/// <summary>Derivatives builder</summary>
public sealed class DerivativesBuilder
{
private readonly string _assemblyName;
private readonly ImmutableArray<MethodInformation> _methodInformation;

public DerivativesBuilder(Compilation compilationUnitSyntax, ImmutableArray<MethodInformation> methodInformation)
{
_assemblyName = compilationUnitSyntax.AssemblyName!;
_methodInformation = methodInformation;
}

public CompilationUnitSyntax GenerateSource()
{
var members = GenerateMembers();
return CreateCompilationUnit(members);
}

private CompilationUnitSyntax CreateCompilationUnit(MemberDeclarationSyntax[] memberDeclarations)
{
return CompilationUnit()
.WithUsings(
SingletonList(
UsingDirective(
QualifiedName(
QualifiedName(
IdentifierName("Mathematics"),
IdentifierName("NET")),
IdentifierName("Core")))
.WithUsingKeyword(
Token(
TriviaList(
Comment("// Auto-generated code")),
SyntaxKind.UsingKeyword,
TriviaList()))))
.WithMembers(
SingletonList<MemberDeclarationSyntax>(
FileScopedNamespaceDeclaration(
QualifiedName(
QualifiedName(
IdentifierName(_assemblyName),
IdentifierName("Generated")),
IdentifierName("Mathematics")))
.WithMembers(
SingletonList<MemberDeclarationSyntax>(
ClassDeclaration("Equations")
.WithModifiers(
TokenList(new[] {
Token(SyntaxKind.PublicKeyword),
Token(SyntaxKind.StaticKeyword) }))
.WithMembers(
List(memberDeclarations))))))
.NormalizeWhitespace();
}

private MemberDeclarationSyntax[] GenerateMembers()
{
var result = new MemberDeclarationSyntax[_methodInformation.Length];
for (int i = 0; i < _methodInformation.Length; i++)
{
var equation = _methodInformation[i].MethodDeclaration.RemoveEquationAttribute();
var transformedEquation = SymbolicsHelper.TransformEquation(equation);
result[i] = transformedEquation;
}
return result;
}
}
Loading

0 comments on commit 07cdd16

Please sign in to comment.