Skip to content

Commit

Permalink
Rename ComplexNumber to Complex
Browse files Browse the repository at this point in the history
- Users should create an alias for Mathematics.NET.Core.Complex if they want to use it along with the complex number type defined in System.Numerics
- Update documentation to reflect this change
- Update tests and benchmarks to reflect this change
  • Loading branch information
HamletTanyavong committed Oct 23, 2023
1 parent 4d1d5b8 commit 10030d5
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 134 deletions.
8 changes: 5 additions & 3 deletions docs/articles/fundamentals/numeric-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@

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\>](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.
All Mathematics.NET numbers implement the `IComplex<T>` 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 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

The type that represents complex numbers in this package shares the same name with the one defined in `System.Numerics.Complex`. Therefore, if we wish to use this library with `System.Numerics`, we need to create an alias to resolve the ambigious reference. Adding the line `using Complex = Mathematics.NET.Core.Complex;` should suffice.

To create a complex number, we can write
```csharp
ComplexNumber z = new(3, 4);
Complex 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
ComplexNumber z = 3;
Complex z = 3;
```
which represents $ z = 3 $.

Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Mathematics.NET/LinearAlgebra/LinAlg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static class LinAlg
/// <example>
/// Suppose we want to find the eigenvalues of a 2x2 matrix. We can write the following to get them:
/// <code language="cs">
/// Span2D&lt;ComplexNumber&gt; matrix = new ComplexNumber[2, 2]
/// Span2D&lt;Complex&gt; matrix = new Complex[2, 2]
/// {
/// { new(1, 2), new(2, 3) },
/// { new(1, -2), new(3, 5) }
Expand Down
2 changes: 1 addition & 1 deletion src/Mathematics.NET/Mathematics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static class Mathematics
//

/// <summary>Represents the imaginary unit, $ i $</summary>
public static ComplexNumber Im => new(Real.Zero, Real.One);
public static Complex Im => new(Real.Zero, Real.One);

/// <inheritdoc cref="Constants.E"/>
public static Real E => Real.E;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ namespace Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks;
[MemoryDiagnoser]
public class ComplexDivisionBenchmarks
{
public ComplexNumber Z { get; set; }
public ComplexNumber W { get; set; }
public Complex Z { get; set; }
public Complex W { get; set; }

public Complex X { get; set; }
public Complex Y { get; set; }
public SystemComplex X { get; set; }
public SystemComplex Y { get; set; }

[GlobalSetup]
public void GlobalSetup()
Expand All @@ -47,13 +47,13 @@ public void GlobalSetup()
}

[Benchmark(Baseline = true)]
public Complex SystemDivision()
public SystemComplex SystemDivision()
{
return X / Y;
}

[Benchmark]
public ComplexNumber ComplexDivision_WithAggressiveInlining()
public Complex ComplexDivision_WithAggressiveInlining()
{
return Z / W;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ namespace Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks;
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
public class ComplexTrigonometryBenchmarks
{
public ComplexNumber Z { get; set; }
public ComplexNumber ImOverTwo { get; set; }
public Complex Z { get; set; }
public Complex ImOverTwo { get; set; }

public Complex W { get; set; }
public SystemComplex W { get; set; }

[GlobalSetup]
public void GlobalSetup()
Expand All @@ -47,26 +47,26 @@ public void GlobalSetup()
}

[Benchmark(Baseline = true)]
public Complex Atan_System()
public SystemComplex Atan_System()
{
return Complex.Atan(W);
return SystemComplex.Atan(W);
}

[Benchmark]
public ComplexNumber Atan_MathNET()
public Complex Atan_MathNET()
{
return ComplexNumber.Atan(Z);
return Complex.Atan(Z);
}

//[Benchmark]
public ComplexNumber Atan_WithoutConstImOverTwo()
public Complex Atan_WithoutConstImOverTwo()
{
return Mathematics.Im / 2.0 * ComplexNumber.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z));
return Mathematics.Im / 2.0 * Complex.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z));
}

//[Benchmark]
public ComplexNumber Atan_WithConstImOverTwo()
public Complex Atan_WithConstImOverTwo()
{
return ImOverTwo * ComplexNumber.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z));
return ImOverTwo * Complex.Ln((Mathematics.Im + Z) / (Mathematics.Im - Z));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ namespace Mathematics.NET.Benchmarks.Core.ComplexNumberBenchmarks;
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
public class SystemComplexAbsVsComplexAbsBenchmarks
{
public Complex Z { get; set; }
public ComplexNumber W { get; set; }
public SystemComplex Z { get; set; }
public Complex W { get; set; }

[GlobalSetup]
public void GlobalSetup()
Expand All @@ -45,12 +45,12 @@ public void GlobalSetup()
[Benchmark(Baseline = true)]
public Real SystemComplexAbs()
{
return Complex.Abs(Z);
return SystemComplex.Abs(Z);
}

[Benchmark]
public ComplexNumber ComplexAbs()
public Complex ComplexAbs()
{
return ComplexNumber.Abs(W);
return Complex.Abs(W);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ public class MatrixMultiplyByScalarBenchmarks
{
public int Rows { get; set; }
public int Cols { get; set; }
public required ComplexNumber[,] MatrixOne { get; set; }
public required ComplexNumber[,] MatrixTwo { get; set; }
public required NET.Core.Complex[,] MatrixOne { get; set; }
public required NET.Core.Complex[,] MatrixTwo { get; set; }

[GlobalSetup]
public void GlobalSetup()
{
Rows = 100;
Cols = 100;

MatrixOne = new ComplexNumber[Rows, Cols];
MatrixOne = new NET.Core.Complex[Rows, Cols];

for (int i = 0; i < Rows; i++)
{
Expand Down Expand Up @@ -75,7 +75,7 @@ public void MultiplyByScalarNaive()
[Benchmark]
public void MultiplyByScalarParallel()
{
Memory2D<ComplexNumber> matrixAsMemory = MatrixTwo;
ParallelHelper.ForEach(matrixAsMemory, new MultiplyByScalarAction<ComplexNumber>(Real.Pi));
Memory2D<NET.Core.Complex> matrixAsMemory = MatrixTwo;
ParallelHelper.ForEach(matrixAsMemory, new MultiplyByScalarAction<NET.Core.Complex>(Real.Pi));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
<Using Include="BenchmarkDotNet.Attributes" />
<Using Include="BenchmarkDotNet.Order" />
<Using Include="Mathematics.NET.Core" />
<Using Include="System.Numerics" />
<Using Include="System.Numerics.Complex">
<Alias>SystemComplex</Alias>
</Using>
</ItemGroup>

</Project>
48 changes: 24 additions & 24 deletions tests/Mathematics.NET.Tests/Core/ComplexTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ public sealed class ComplexTests
[DataRow(1.23, 2.34, 1.114564084931578, -1.686112230652994)]
public void Acos_Complex_ReturnsComplex(double inReal, double inImaginary, double expectedRe, double expectedIm)
{
ComplexNumber input = new(inReal, inImaginary);
Complex input = new(inReal, inImaginary);

var actualResult = ComplexNumber.Acos(input);
var actualResult = Complex.Acos(input);
var actualRe = actualResult.Re.Value;
var actualIm = actualResult.Im.Value;

Expand All @@ -49,9 +49,9 @@ public void Acos_Complex_ReturnsComplex(double inReal, double inImaginary, doubl
[DataRow(1.23, 2.34, 4.562322418633185e-1, 1.686112230652994)]
public void Asin_Complex_ReturnsComplex(double inReal, double inImaginary, double expectedRe, double expectedIm)
{
ComplexNumber input = new(inReal, inImaginary);
Complex input = new(inReal, inImaginary);

var actualResult = ComplexNumber.Asin(input);
var actualResult = Complex.Asin(input);
var actualRe = actualResult.Re.Value;
var actualIm = actualResult.Im.Value;

Expand All @@ -63,9 +63,9 @@ public void Asin_Complex_ReturnsComplex(double inReal, double inImaginary, doubl
[DataRow(1.23, 2.34, 1.37591078602063, 3.356559207392595e-1)]
public void Atan_Complex_ReturnsComplex(double inReal, double inImaginary, double expectedRe, double expectedIm)
{
ComplexNumber input = new(inReal, inImaginary);
Complex input = new(inReal, inImaginary);

var actualResult = ComplexNumber.Atan(input);
var actualResult = Complex.Atan(input);
var actualRe = actualResult.Re.Value;
var actualIm = actualResult.Im.Value;

Expand All @@ -77,10 +77,10 @@ public void Atan_Complex_ReturnsComplex(double inReal, double inImaginary, doubl
[DataRow(1.2, 2.3, 1.2, -2.3)]
public void Conjugate_Complex_ReturnsConjugate(double inReal, double inImaginary, double outReal, double outImaginary)
{
ComplexNumber input = new(inReal, inImaginary);
ComplexNumber expected = new(outReal, outImaginary);
Complex input = new(inReal, inImaginary);
Complex expected = new(outReal, outImaginary);

var actual = ComplexNumber.Conjugate(input);
var actual = Complex.Conjugate(input);

Assert.AreEqual(expected, actual);
}
Expand All @@ -92,8 +92,8 @@ public void Conjugate_Complex_ReturnsConjugate(double inReal, double inImaginary
[DataRow(5, 3.5, 7, 0, 0.7142857142857142, 0.5)]
public void Division_Complexs_ReturnsComplex(double dividendRe, double dividendIm, double divisorRe, double divisorIm, double expectedRe, double expectedIm)
{
ComplexNumber dividend = new(dividendRe, dividendIm);
ComplexNumber divisor = new(divisorRe, divisorIm);
Complex dividend = new(dividendRe, dividendIm);
Complex divisor = new(divisorRe, divisorIm);

var actualResult = dividend / divisor;
var actualRe = actualResult.Re.Value;
Expand All @@ -107,7 +107,7 @@ public void Division_Complexs_ReturnsComplex(double dividendRe, double dividendI
[DataRow(3, 4, 5)]
public void Magnitude_Complex_ReturnsMagnitude(double inReal, double inImaginary, double expected)
{
ComplexNumber z = new(inReal, inImaginary);
Complex z = new(inReal, inImaginary);

var actual = z.Magnitude.Value;

Expand All @@ -121,7 +121,7 @@ public void Magnitude_Complex_ReturnsMagnitude(double inReal, double inImaginary
[DataRow(-1, -1, -Math.PI, -Math.PI / 2)]
public void Phase_Complex_ReturnsAngleInCorrectQuadrant(double inReal, double inImaginary, double expectedMin, double expectedMax)
{
ComplexNumber z = new(inReal, inImaginary);
Complex z = new(inReal, inImaginary);

var actual = z.Phase.Value;

Expand All @@ -133,10 +133,10 @@ public void Phase_Complex_ReturnsAngleInCorrectQuadrant(double inReal, double in
[DataRow(1.5, 2.5, 1.76470588235294117e-1, -2.94117647058823529e-1)]
public void Reciprocate_Complex_ReturnsReciprocal(double inReal, double inImaginary, double expectedRe, double expectedIm)
{
ComplexNumber z = new(inReal, inImaginary);
ComplexNumber expected = new(expectedRe, expectedIm);
Complex z = new(inReal, inImaginary);
Complex expected = new(expectedRe, expectedIm);

var actual = ComplexNumber.Reciprocate(z);
var actual = Complex.Reciprocate(z);

Assert.AreEqual(expected, actual);
}
Expand All @@ -148,7 +148,7 @@ public void Reciprocate_Complex_ReturnsReciprocal(double inReal, double inImagin
[DataRow(7.345, 124.841, "IM", "124.841")]
public void ToString_Complex_ReturnsString(double inReal, double inImaginary, string? format, string expected)
{
ComplexNumber z = new(inReal, inImaginary);
Complex z = new(inReal, inImaginary);

var actual = z.ToString(format, null);

Expand All @@ -160,7 +160,7 @@ public void ToString_Complex_ReturnsString(double inReal, double inImaginary, st
[DataRow(1.23, 2.34, 12)]
public void TryFormat_ComplexWithAdequateDestinationLength_ReturnsTrue(double inReal, double inImaginary, int length)
{
ComplexNumber z = new(inReal, inImaginary);
Complex z = new(inReal, inImaginary);

Span<char> span = new char[length];
var actual = z.TryFormat(span, out int _, null, null);
Expand All @@ -173,7 +173,7 @@ public void TryFormat_ComplexWithAdequateDestinationLength_ReturnsTrue(double in
[DataRow(1.23, 2.34, 11)]
public void TryFormat_ComplexWithInadequateDestinationLength_ReturnsFalse(double inReal, double inImaginary, int length)
{
ComplexNumber z = new(inReal, inImaginary);
Complex z = new(inReal, inImaginary);

Span<char> span = new char[length];
var actual = z.TryFormat(span, out int _, null, null);
Expand All @@ -188,9 +188,9 @@ public void TryFormat_ComplexWithInadequateDestinationLength_ReturnsFalse(double
[DataRow("( 1.23 , 3.45 )", 1.23, 3.45)]
public void TryParse_SpanOfChar_ReturnsComplex(string s, double expectedRe, double expectedIm)
{
ComplexNumber expected = new(expectedRe, expectedIm);
Complex expected = new(expectedRe, expectedIm);

_ = ComplexNumber.TryParse(s.AsSpan(), null, out ComplexNumber actual);
_ = Complex.TryParse(s.AsSpan(), null, out Complex actual);

Assert.AreEqual(expected, actual);
}
Expand All @@ -202,7 +202,7 @@ public void TryParse_SpanOfChar_ReturnsComplex(string s, double expectedRe, doub
[DataRow("(0,0")]
public void TryParse_SpanOfChar_ReturnsFalse(string s)
{
var actual = ComplexNumber.TryParse(s.AsSpan(), null, out _);
var actual = Complex.TryParse(s.AsSpan(), null, out _);

Assert.IsFalse(actual);
}
Expand All @@ -221,7 +221,7 @@ public void TryParse_SpanOfChar_ReturnsFalse(string s)
[DataRow(1.2345, 0, 8, 8)]
public void TryFormat_ComplexWithInadequateDestinationLength_ReturnsCorrectNumberOfCharsWritten(double inReal, double inImaginary, int length, int expected)
{
ComplexNumber z = new(inReal, inImaginary);
Complex z = new(inReal, inImaginary);

Span<char> span = new char[length];
_ = z.TryFormat(span, out int actual, null, null);
Expand All @@ -236,7 +236,7 @@ public void TryFormat_ComplexWithInadequateDestinationLength_ReturnsCorrectNumbe
[DataRow(1.2, 7, 1, "IM", "7")]
public void TryFormat_Complex_ReturnsSpanOfCharacters(double inReal, double inImaginary, int length, string? format, string expected)
{
ComplexNumber z = new(inReal, inImaginary);
Complex z = new(inReal, inImaginary);

Span<char> actual = new char[length];
_ = z.TryFormat(actual, out int _, format, null);
Expand Down
4 changes: 2 additions & 2 deletions tests/Mathematics.NET.Tests/LinearAlgebra/LinAlgTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static IEnumerable<object[]> GetComplexInputs()
{
yield return new[]
{
new ComplexNumber[2, 2]
new Complex[2, 2]
{
{ new(1, 2), new(2, 3) },
{ new(1, -2), new(3, 5) }
Expand All @@ -65,7 +65,7 @@ public static IEnumerable<object[]> GetRealInputs()

[TestMethod]
[DynamicData(nameof(GetComplexInputs), DynamicDataSourceType.Method)]
public void QRGramSchmidt_MatrixOfComplex_ReturnsQRDecompositionOfMatrix(ComplexNumber[,] matrix)
public void QRGramSchmidt_MatrixOfComplex_ReturnsQRDecompositionOfMatrix(Complex[,] matrix)
=> QRGramSchmidt_Helper_MatrixOfGeneric_ReturnsQRDecompositionOfMatrix(matrix);

[TestMethod]
Expand Down

0 comments on commit 10030d5

Please sign in to comment.