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
4 changes: 3 additions & 1 deletion BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,8 @@ other a parse error.** They are `1 + 1/2^m + ... + 1/n^m` for a whole `n >= 0`,
`ζ(m) - ζ(m, n + 1)` elsewhere, as Mathematica's `HarmonicNumber` is: `ψ(n + 1) - ψ(1)` for `m = 1`, evaluated numerically
through `digamma` and `polygamma` for a whole `m >= 1`, and exactly at a half-whole `n` for `m = 1` or an even `m`. A
negative integer `n` has no value but for a whole `m <= 0`
([#2182](https://github.com/asc-community/AngouriMath/issues/2182)).
([#2182](https://github.com/asc-community/AngouriMath/issues/2182)). They compile, on the same terms, in both compilers
([#2195](https://github.com/asc-community/AngouriMath/issues/2195)).

| Input | Was (2.6.0) | Now |
|---|---|---|
Expand Down Expand Up @@ -866,6 +867,7 @@ no others. Where that proof does not go through, or a bound is symbolic, the int
- **Derivatives.** Each order differentiates to the next. The derivative of `x!`, which was left unevaluated, is `x! * digamma(x + 1)` ([#171](https://github.com/asc-community/AngouriMath/issues/171)).
- **Integrals.** Each order integrates to the one before, and `digamma(x)` to `ln((x - 1)!)`.
- **Exact values.** An odd order at a whole or half-whole argument is a rational times a power of `pi` plus a rational: `polygamma(1, 1)` is `1/6 * pi ^ 2`. The digamma function there is a rational less Euler's constant, and at a half-whole argument less `2 ln 2` as well: `digamma(1)` is `-eulergamma`.
- **Compiled forms.** Each compiles, in double precision and by the same reflection, recurrence and asymptotic series, in both compilers ([#2195](https://github.com/asc-community/AngouriMath/issues/2195)).

| Input | Was (2.6.0) | Now |
|---|---|---|
Expand Down
6 changes: 6 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,12 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[Tests/UnitTests/Common/LambertWCompilationTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[AngouriMath/Numerics/PolygammaFunction.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[Tests/UnitTests/Common/PolygammaCompilationTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[Tests/UnitTests/Common/CompileMatrixTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

Expand Down
25 changes: 25 additions & 0 deletions Sources/AngouriMath/Functions/Compilation/IntoFE/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,31 @@ private protected override void CompileNode(Compiler compiler)
}
}

// The polygamma functions and the harmonic numbers. https://github.com/asc-community/AngouriMath/issues/2195
public partial record Polygammaf
{
private protected override bool CompilesItself => true;

private protected override void CompileNode(Compiler compiler)
{
Argument.InnerCompile(compiler);
Order.InnerCompile(compiler);
compiler.Instructions.Add(new(InstructionType.CALL_POLYGAMMA));
}
}

public partial record HarmonicNumberf
{
private protected override bool CompilesItself => true;

private protected override void CompileNode(Compiler compiler)
{
Order.InnerCompile(compiler);
Argument.InnerCompile(compiler);
compiler.Instructions.Add(new(InstructionType.CALL_HARMONIC_NUMBER));
}
}

public partial record Maxf
{
private protected override bool CompilesItself => true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ internal enum InstructionType
CALL_FALLING_FACTORIAL,
CALL_RISING_FACTORIAL,
CALL_LAMBERTW,
CALL_POLYGAMMA,
CALL_HARMONIC_NUMBER,

// 3-arg: a value where its predicate holds, and the one below it elsewhere.
CALL_SELECT = 150,
Expand Down Expand Up @@ -359,6 +361,12 @@ public System.Numerics.Complex Substitute(params System.Numerics.Complex[] value
case InstructionType.CALL_LAMBERTW:
stack.Push(AngouriMath.Numerics.LambertWFunction.LambertW(stack.Pop(), stack.Pop()));
break;
case InstructionType.CALL_POLYGAMMA:
stack.Push(AngouriMath.Numerics.PolygammaFunction.Polygamma(stack.Pop(), stack.Pop()));
break;
case InstructionType.CALL_HARMONIC_NUMBER:
stack.Push(AngouriMath.Numerics.PolygammaFunction.HarmonicNumber(stack.Pop(), stack.Pop()));
break;
case InstructionType.CALL_DOUBLE_FACTORIAL:
stack.Push(AngouriMath.Numerics.CombinatorialFunctions.DoubleFactorial(stack.Pop()));
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ RisingFactorialf when ShouldBeAtLeastDouble(left) is var newLeft && ShouldBeAtLe
=> Expression.Call(GetDef("RisingFactorial", 2, newLeft.Type), newLeft, newRight),
LambertWf when ShouldBeAtLeastDouble(left) is var newLeft && ShouldBeAtLeastDouble(right) is var newRight
=> Expression.Call(GetDef("LambertW", 2, newLeft.Type), newLeft, newRight),
Polygammaf when ShouldBeAtLeastDouble(left) is var newLeft && ShouldBeAtLeastDouble(right) is var newRight
=> Expression.Call(GetDef("Polygamma", 2, newLeft.Type), newLeft, newRight),
HarmonicNumberf when ShouldBeAtLeastDouble(left) is var newLeft && ShouldBeAtLeastDouble(right) is var newRight
=> Expression.Call(GetDef("HarmonicNumber", 2, newLeft.Type), newLeft, newRight),
Maxf => Expression.Call(GetDef("Max", 2, left.Type), left, right),
Minf => Expression.Call(GetDef("Min", 2, left.Type), left, right),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ public static System.Numerics.Complex Round(System.Numerics.Complex a)
public static System.Numerics.Complex LambertW(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.LambertWFunction.LambertW(a, b);
public static double LambertW(double a, double b) => AngouriMath.Numerics.LambertWFunction.LambertW(a, b);

// The polygamma functions of a whole order, and the harmonic numbers.
// https://github.com/asc-community/AngouriMath/issues/2195
public static System.Numerics.Complex Polygamma(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.PolygammaFunction.Polygamma(a, b);
public static double Polygamma(double a, double b) => AngouriMath.Numerics.PolygammaFunction.Polygamma(a, b);
public static System.Numerics.Complex HarmonicNumber(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.PolygammaFunction.HarmonicNumber(a, b);
public static double HarmonicNumber(double a, double b) => AngouriMath.Numerics.PolygammaFunction.HarmonicNumber(a, b);

/// <summary>
/// True where <c>System.Numerics.Complex.IsNaN</c> is, spelled out because that overload is
/// .NET 7 and later and this assembly also targets netstandard2.0. A complex number is NaN
Expand Down Expand Up @@ -540,7 +547,11 @@ public static bool IsNaN(System.Numerics.Complex a)
{ ("RisingFactorial", 2, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>((a, b) => RisingFactorial(a, b)) },
{ ("RisingFactorial", 2, typeof(double)), Def<double>((a, b) => RisingFactorial(a, b)) },
{ ("LambertW", 2, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>((a, b) => LambertW(a, b)) },
{ ("Polygamma", 2, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>((a, b) => Polygamma(a, b)) },
{ ("HarmonicNumber", 2, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>((a, b) => HarmonicNumber(a, b)) },
{ ("LambertW", 2, typeof(double)), Def<double>((a, b) => LambertW(a, b)) },
{ ("Polygamma", 2, typeof(double)), Def<double>((a, b) => Polygamma(a, b)) },
{ ("HarmonicNumber", 2, typeof(double)), Def<double>((a, b) => HarmonicNumber(a, b)) },
};

// An expression tree is how C# spells "the MethodInfo of this method" without a string:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ namespace AngouriMath.Core.Compilation.IntoLinq
public static System.Numerics.Complex LambertW(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.LambertWFunction.LambertW(a, b);
public static double LambertW(double a, double b) => AngouriMath.Numerics.LambertWFunction.LambertW(a, b);

// The polygamma functions of a whole order, and the harmonic numbers.
// https://github.com/asc-community/AngouriMath/issues/2195
public static System.Numerics.Complex Polygamma(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.PolygammaFunction.Polygamma(a, b);
public static double Polygamma(double a, double b) => AngouriMath.Numerics.PolygammaFunction.Polygamma(a, b);
public static System.Numerics.Complex HarmonicNumber(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.PolygammaFunction.HarmonicNumber(a, b);
public static double HarmonicNumber(double a, double b) => AngouriMath.Numerics.PolygammaFunction.HarmonicNumber(a, b);

/// <summary>
/// True where <c>System.Numerics.Complex.IsNaN</c> is, spelled out because that overload is
/// .NET 7 and later and this assembly also targets netstandard2.0. A complex number is NaN
Expand Down Expand Up @@ -293,6 +300,8 @@ namespace AngouriMath.Core.Compilation.IntoLinq
<# } #>
<# foreach (var type in new[]{ "System.Numerics.Complex", "double" }) { #>
{ ("LambertW", 2, typeof(<#= type #>)), Def<<#= type #>>((a, b) => LambertW(a, b)) },
{ ("Polygamma", 2, typeof(<#= type #>)), Def<<#= type #>>((a, b) => Polygamma(a, b)) },
{ ("HarmonicNumber", 2, typeof(<#= type #>)), Def<<#= type #>>((a, b) => HarmonicNumber(a, b)) },
<# } #>
};

Expand Down
Loading
Loading