Skip to content
Merged
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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The examples below highlight some of the features of Mathematics.NET.
Rational numbers can be created using

```csharp
Rational<int> number = new(4, 6);
Rational<int, double> number = new(4, 6);
```

Besides the basic arithmetic operations, operations on rational numbers include, but are not limited to, the following:
Expand All @@ -45,7 +45,7 @@ Support for automatic differentiation (autodiff) is provided by gradient tapes,
Reverse-mode automatic differentiation can be performed using gradient tapes. To create a gradient tape, use

```csharp
GradientTape<Real> tape = new();
GradientTape<Real<double>, double> tape = new();
```

Variables can be created using the `CreateVariable` method. To work with functions of three variables with intial values $x=1.23$, $y=0.66$, and $z=2.34$, write
Expand Down Expand Up @@ -96,7 +96,7 @@ Console.WriteLine($"df/dz = {gradient[2]}");
We can use Hessian tapes to perform second-order, reverse-mode automatic differentiation. To create a Hessian tape, use

```csharp
HessianTape<Real> tape = new();
HessianTape<Real<double>, double> tape = new();
```

Then, we can use the `CreateAutoDiffVector` method to create a vector with initial values. Write
Expand Down Expand Up @@ -139,11 +139,11 @@ tape.ReverseAccumulate(out var gradient, our var hessian);
Finally, use those values to compute our Laplacian.

```csharp
var u = Real.One / (x.X1.Value * Real.Sin(x.X2.Value)); // 1 / (r * Sin(θ))
var u = Real<double>.One / (x.X1.Value * Real<double>.Sin(x.X2.Value)); // 1 / (r * Sin(θ))
var laplacian =
2.0 * gradient[0] / x.X1.Value +
hessian[0, 0] +
u * Real.Cos(x.X2.Value) * gradient[1] / x.X1.Value +
u * Real<double>.Cos(x.X2.Value) * gradient[1] / x.X1.Value +
hessian[1, 1] / (x.X1.Value * x.X1.Value) +
u * u * hessian[2, 2];

Expand Down
36 changes: 21 additions & 15 deletions docs/src/app/autodiff/forward-mode-autodiff/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ First-order, forward-mode autodiff can be performed using [dual numbers](https:/
Forward-mode autodiff can be performed through the use of dual numbers which keep track of derivatives from our calculations. To create a dual number in Mathematics.NET, we provide a *primal* and *tangent* part; if no tangent part is provided, it will automatically be set to zero.

```csharp
Dual<Real> x = new(1.23, 1.0);
Dual<Real> y = new(2.34);
Dual<Real<double>, double> x = new(1.23, 1.0);
Dual<Real<double>, double> y = new(2.34);
```

The primal part represents the point at which we want to compute our derivative, while the tangent part holds the information about our derivative. When we create a dual number with a tangent part, we specify a value that will be used as the seed. (It is important to know that the value of the derivative changes proportionally with this value.) We can also write, equivalently,

```csharp
using static Mathematics.NET.AutoDiff.Dual<Mathematics.NET.Core.Real>;
using static Mathematics.NET.AutoDiff.Dual<Mathematics.NET.Real<double>, double>;

var x = CreateVariable(1.23, 1.0);
var y = CreateVariable(2.34);
Expand All @@ -40,8 +40,8 @@ $$
at the points $ x=1.23 $ and $ y=2.34 $ with respect to $ x $. We write

```csharp
Dual<Real> x = CreateVariable(1.23, 1.0);
Dual<Real> y = CreateVariable(2.34);
Dual<Real<double>, double> x = CreateVariable(1.23, 1.0);
Dual<Real<double>, double> y = CreateVariable(2.34);

var result = Sin(x + y) * Exp(-y) / (x * x + y * y + 1);

Expand All @@ -51,8 +51,8 @@ Console.WriteLine("∂f/∂x: {0}", result);
Notice that we set the seed for the variable of interest, $ x $, to 1 while the seed for the variable we do not care about, $ y $, was set to 0. If we had set both to 1.0, then we would have computed the total derivative of the function instead. To compute the partial derivative of our function with respect to $ y $, we write

```csharp
Dual<Real> x = CreateVariable(1.23);
Dual<Real> y = CreateVariable(2.34, 1.0);
Dual<Real<double>, double> x = CreateVariable(1.23);
Dual<Real<double>, double> y = CreateVariable(2.34, 1.0);
```

with the tangent part of the variable of interest set to 1 and the other to 0. Doing this will print the following to the console:
Expand All @@ -67,8 +67,8 @@ with the tangent part of the variable of interest set to 1 and the other to 0. D
To get the total derivate of a function, set the seeds for each variable to `1.0`:

```csharp
Dual<Real> x = CreateVariable(1.23, 1.0);
Dual<Real> y = CreateVariable(2.34, 1.0);
Dual<Real<double>, double> x = CreateVariable(1.23, 1.0);
Dual<Real<double>, double> y = CreateVariable(2.34, 1.0);
// Repeat for each variable present
```

Expand All @@ -77,7 +77,10 @@ Dual<Real> y = CreateVariable(2.34, 1.0);
We can create autodiff vectors to help us keep track of multiple dual numbers.

```csharp
AutoDiffVector3<Real> x = new(CreateVariable(1.23), CreateVariable(0.66), CreateVariable(2.34));
AutoDiffVector3<Dual<Real<double>, double>, Real<double>, double> x = new(
CreateVariable(1.23),
CreateVariable(0.66),
CreateVariable(2.34));
```

We can use this to compute the vector-Jacobian product of the vector functions
Expand All @@ -95,10 +98,13 @@ $$
with the vector $ v=(0.23,1.57,-1.71) $ at our points $ x_1=1.23 $, $ x_2=0.66 $, and $ x_3=2.34 $ by writing

```csharp
AutoDiffVector3<Real> x = new(CreateVariable(1.23), CreateVariable(0.66), CreateVariable(2.34));
Vector3<Real> v = new(0.23, 1.57, -1.71);
AutoDiffVector3<Dual<Real<double>, double>, Real<double>, double> x = new(
CreateVariable(1.23),
CreateVariable(0.66),
CreateVariable(2.34));
Vector3<Real<double>, double> v = new(0.23, 1.57, -1.71);

var result = AutoDiffVector3<Real>.VJP(
var result = AutoDiffVector3<Dual<Real<double>, double>, Real<double>, double>.VJP(
v,
x => Sin(x.X1) * (Cos(x.X2) + Sqrt(x.X3)),
x => Sqrt(x.X1 + x.X2 + x.X3),
Expand All @@ -125,9 +131,9 @@ $$
with respect to $ z $, at the points $ z=1.23+i0.66 $ and $ w=2.34-i0.25 $. We can do so by writing

```csharp
using Mathematics.NET;
using Mathematics.NET.AutoDiff;
using Mathematics.NET.Core;
using static Mathematics.NET.AutoDiff.HyperDual<Mathematics.NET.Core.Complex>;
using static Mathematics.NET.AutoDiff.HyperDual<Mathematics.NET.Complex<double>, double>;

var z = CreateVariable(new(1.23, 0.66), 1.0, 1.0);
var w = CreateVariable(new(2.34, -0.25));
Expand Down
48 changes: 20 additions & 28 deletions docs/src/app/autodiff/reverse-mode-autodiff/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ Gradient tapes keep track of operations and their contributions to the gradient;
First, import the following namespaces:

```csharp {{ title: 'Imports' }}
using Mathematics.NET;
using Mathematics.NET.AutoDiff;
using Mathematics.NET.Core;
```

Then, we can create the tape with

```csharp
GradientTape<Real> tape = new();
GradientTape<Real<double>, double> tape = new();
var x = tape.CreateVariable(1.23);
```

Expand All @@ -42,7 +42,7 @@ var z = tape.CreateVariable(2.34);
To simplify this process, we may instead choose to create a vector of variables.

```csharp
AutoDiffVector3 x = tape.CreateAutoDiffVector(1.23, 0.66, 2.34);
var x = tape.CreateAutoDiffVector(1.23, 0.66, 2.34);
```

Once we are satisfied, we may use these in our equations.
Expand All @@ -63,7 +63,7 @@ at the point $ x=1.23 $. We can write
var result = tape.Divide(
tape.Multiply(tape.Sin(x), tape.Ln(x)),
tape.Exp(
tape.Multiply(-Real.One, x)));
tape.Multiply(-Real<double>.One, x)));
```

which will give us the value of the function at our specified point. At this moment, the derivative has not been calculated, but we are, however, able to examine the nodes that have been added to our tape. We can use [`LogNodes`](https://github.com/HamletTanyavong/Mathematics.NET/blob/42cb7ec544baafeca6bd842dfb5ddd8634179593/src/Mathematics.NET/AutoDiff/GradientTape.cs#L118) to do so, provided we have a logger.
Expand Down Expand Up @@ -220,7 +220,7 @@ As before, we can use `ReverseAccumulate` to get our gradients and write them to

```csharp
tape.ReverseAccumulate(out var gradient);
Console.WriteLine(gradient.ToDisplayString()); // [-0.8243135949243512, -0.13023459678281554, 0.2382974299363868 ]
Console.WriteLine(gradient.ToString<Real<double>, double, double>()); // [-0.8243135949243512, -0.13023459678281554, 0.2382974299363868 ]
```

which, for clarity, represents the following equations:
Expand Down Expand Up @@ -258,24 +258,22 @@ $$
and the vector $ \textbf{v} = (0.23, 1.57, -1.71) $ for $ x_1,x_2,x_3>0 $. Here is the code:

```csharp
using Mathematics.NET.AutoDiff;

GradientTape<Real> tape = new();
GradientTape<Real<double>, double> tape = new();
var x = tape.CreateAutoDiffVector(1.23, 0.66, 2.34);
Vector3<Real> v = new(0.23, 1.57, -1.71);

_ = tape.JVP(F1, F2, F3, x, v);

// f(x, y, z) = Sin(x) * (Cos(y) + Sqrt(z))
static Variable F1(GradientTape tape, AutoDiffVector3 x)
static Variable F1(GradientTape<Real<double>, double> tape, AutoDiffVector3<Real<double>, double> x)
{
return tape.Multiply(
tape.Sin(x.X1),
tape.Add(tape.Cos(x.X2), tape.Sqrt(x.X3)));
}

// f(x, y, z) = Sqrt(x + y + z)
static Variable F2(GradientTape tape, AutoDiffVector3 x)
static Variable F2(GradientTape<Real<double>, double> tape, AutoDiffVector3<Real<double>, double> x)
{
return tape.Sqrt(
tape.Add(
Expand All @@ -284,7 +282,7 @@ static Variable F2(GradientTape tape, AutoDiffVector3 x)
}

// f(x, y, z) = Sinh(Exp(x) * y / z)
static Variable F3(GradientTape tape, AutoDiffVector3 x)
static Variable F3(GradientTape<Real<double>, double> tape, AutoDiffVector3<Real<double>, double> x)
{
return tape.Sinh(
tape.Multiply(
Expand All @@ -306,10 +304,7 @@ $$
at the points $ z=1.23+i2.34 $ and $ w=-0.66+i0.23 $. We can write

```csharp
using Mathematics.NET.AutoDiff;
using Mathematics.NET.Core;

GradientTape<Complex> tape = new();
GradientTape<Complex<double>, double> tape = new();
var z = tape.CreateVariable(new(1.23, 2.34));
var w = tape.CreateVariable(new(-0.66, 0.23));

Expand All @@ -327,7 +322,7 @@ tape.ReverseAccumulate(out var gradient);
// The value of the function at the point z = 1.23 + i2.34 and w = -0.66 + i0.23
Console.WriteLine("Value: {0}", result);
// The gradient of the function: ∂f/∂z and ∂f/∂w, respectively
Console.WriteLine("Gradient: {0}", gradient.ToDisplayString());
Console.WriteLine("Gradient: {0}", gradient.ToString<Complex<double>, double, double>());
```

This is similar to the code we would have written in the real number case. (Note that some methods such as `Atan2` are not available for complex gradient tapes.) This outputs the following to the console:
Expand Down Expand Up @@ -361,17 +356,17 @@ Gradient: [(126.28638563049401, -98.74954259806483), (-38.801295827094066, -109
If there is a function we need that is not provided in the class, we are still able to use it for our gradient tape provided we know its derivative. Suppose, for example, we did not have the `Sin` method. Since we know its derivative is `Cos`, we could write the following:

```csharp
GradientTape tape = new();
GradientTape<Real<double>, double> tape = new();
var x = tape.CreateVariable(1.23);

var result = tape.Operation(
x, // A variable
x => Real.Sin(x), // The function
x => Real.Cos(x)); // The derivative of the function
x, // A variable
x => Real<double>.Sin(x), // The function
x => Real<double>.Cos(x)); // The derivative of the function

tape.ReverseAccumulate(out var gradient);
Console.WriteLine("Value: {0}", result);
Console.WriteLine("Gradient: {0}", gradient.ToDisplayString());
Console.WriteLine("Gradient: {0}", gradient.ToString<Real<double>, double, double>());
```

For custom binary operations in general, we can write
Expand Down Expand Up @@ -401,7 +396,7 @@ Second-order, reverse-mode autodiff can be performed using [Hessian tapes](https
The steps needed to perform second-order, reverse-mode autodiff is similar to the steps needed to perform the first-order case. This time, however, we have access to the following overloads and/or versions of [ReverseAccumulate](https://github.com/HamletTanyavong/Mathematics.NET/blob/42cb7ec544baafeca6bd842dfb5ddd8634179593/src/Mathematics.NET/AutoDiff/HessianTape.cs#L165):

```csharp
HessianTape<Complex> tape = new();
HessianTape<Complex<double>, double> tape = new();

// Do some math...

Expand Down Expand Up @@ -433,10 +428,7 @@ $$
we can write

```csharp
using Mathematics.NET.AutoDiff;
using Mathematics.NET.Core;

HessianTape<Real> tape = new();
HessianTape<Real<double>, double> tape = new();
var x = tape.CreateAutoDiffVector(1.23, 0.66, 0.23);

// f(r, θ, ϕ) = cos(r) / ((r + θ) * sin(ϕ))
Expand All @@ -449,11 +441,11 @@ _ = tape.Divide(
tape.ReverseAccumulate(out var gradient, out var hessian);

// Manual Laplacian computation
var u = Real.One / (x.X1.Value * Real.Sin(x.X2.Value)); // 1 / (r * sin(θ))
var u = Real<double>.One / (x.X1.Value * Real<double>.Sin(x.X2.Value)); // 1 / (r * sin(θ))
var laplacian =
2.0 * gradient[0] / x.X1.Value +
hessian[0, 0] +
u * Real.Cos(x.X2.Value) * gradient[1] / x.X1.Value +
u * Real<double>.Cos(x.X2.Value) * gradient[1] / x.X1.Value +
hessian[1, 1] / (x.X1.Value * x.X1.Value) +
u * u * hessian[2, 2];

Expand Down
22 changes: 15 additions & 7 deletions docs/src/app/fundamentals/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,16 @@ Learn about the fundamentals of Mathematics.NET below. {{ className: 'lead' }}

## Numeric Types

All numeric types in Mathematics.NET implement the [`IComplex`](https://github.com/HamletTanyavong/Mathematics.NET/blob/main/src/Mathematics.NET/Core/IComplex.cs) interface. Unlike [`INumberBase`](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs), this interface defines the method `Conjugate`, which makes operations that accept either complex or real numbers as parameters more robust.
All numeric types in Mathematics.NET implement the [`IComplex`](https://github.com/HamletTanyavong/Mathematics.NET/blob/main/src/Mathematics.NET/Core/IComplex.cs) interface. Unlike [`INumberBase`](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs), this interface defines the method `Conjugate`, which makes operations that accept either complex or real numbers as parameters more robust. To create a numeric type, users must also specify a backing type that implements the `IBinaryNumber` interface. This means `int`, `BigInteger`, and `double` are all valid backing types.

### Complex Numbers

Because the [complex number type](https://github.com/HamletTanyavong/Mathematics.NET/blob/main/src/Mathematics.NET/Core/Complex.cs) in this library shares the name with .NET's own implementation, use the following statement to avoid conflicts:
Complex numbers are represented by the [Complex](https://github.com/HamletTanyavong/Mathematics.NET/blob/main/src/Mathematics.NET/Core/Complex.cs) type. Basic methods and properties made available include `Conjugate`, `Magnitude`, and `Phase`. To create a complex number, write

```csharp
using Complex = Mathematics.NET.Core.Complex;
Complex<double> z = new(1.23, 4.56);
```

Basic methods and properties made available include `Conjugate`, `Magnitude`, and `Phase`.

<div className="not-prose">
<Button href="/resources/core/complex" variant="text" arrow="right">
<>Read more</>
Expand All @@ -29,10 +27,20 @@ Basic methods and properties made available include `Conjugate`, `Magnitude`, an

### Real Numbers

Real numbers are represented by the [Real](https://github.com/HamletTanyavong/Mathematics.NET/blob/main/src/Mathematics.NET/Core/Real.cs) type. It implements the `IReal` interface, which inherits from `IComplex`, and contains additional methods such as `Max` and `Min`.
Real numbers are represented by the [Real](https://github.com/HamletTanyavong/Mathematics.NET/blob/main/src/Mathematics.NET/Core/Real.cs) type. It implements the `IReal` interface, which inherits from `IComplex`, and contains additional methods such as `Max` and `Min`. To create a real number, write

```csharp
Real<double> x = new(1.23);
```

### Rational Numbers

Rational numbers are represented by the [Rational](https://github.com/HamletTanyavong/Mathematics.NET/blob/main/src/Mathematics.NET/Core/Rational.cs) type. This type implements the `IRational` interface, which inherits from `IReal`, and contains addition methods such as `Reciprocate` and `GCD`. Rationals accept any backing type that implements the `IBinaryInteger` and `ISignedNumber` interfaces. This includes `BigInteger`, which should be used carefully due to its performance implications.

Methods and properties made available include `Num`, `Den`, `Reduce`, and `Reciprocate`.
Methods and properties made available include `Num`, `Den`, `Reduce`, and `Reciprocate`. To create a rational number, write

```csharp
Rational<int, double> r = new(1, 2);
```

Rationals also have a second generic type parameter that accepts any value that implements the `IBinaryFloatingPointIeee754` interface. This allows for methods such as `Norm` to return valid results.
Loading
Loading