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
15 changes: 15 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,21 @@ factorial has no value off the whole numbers or at a negative even one
| `"binomial(x, 2)".ToEntity().Compile("x").Call(5)` | `UncompilableNodeException` | `(10, 0)` |
| `"binomial(x, 1/2)".ToEntity().Compile<double, double>("x")(3)` | `UncompilableNodeException` | `2.037183271576257` |

### The number-theoretic functions compile

**Not silent: what was refused is compiled.** `prime` and `valuation` were refused by both compilers with
`UncompilableNodeException`, and `mobius`, `divisorsigma`, `primenu`, `primeomega` and `primepi`, new since 2.6.0,
compile from the start. Each compiles by the routines the interpreter uses, exactly at a whole argument and to `NaN` at
any other, as evaluation gives. A number too large to factorise, and a prime past the millionth, are `NaN` where the
interpreter leaves them as written ([#2195](https://github.com/asc-community/AngouriMath/issues/2195)).

| Input | Was (2.6.0) | Now |
|---|---|---|
| `"prime(x)".ToEntity().Compile("x").Call(10)` | `UncompilableNodeException` | `(29, 0)` |
| `"prime(x)".ToEntity().Compile<double, double>("x")(2.5)` | `UncompilableNodeException` | `NaN` |
| `"valuation(x, 2)".ToEntity().Compile("x").Call(12)` | `UncompilableNodeException` | `(2, 0)` |
| `"valuation(x, 2)".ToEntity().Compile<double, double>("x")(0)` | `UncompilableNodeException` | `Infinity` |

### `mod` compiles over `Complex`

**Not silent: what was refused is compiled.** `Compile<Complex, ...>` refused `mod` with `UncompilableNodeException`,
Expand Down
6 changes: 6 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,12 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[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

[AngouriMath/Numerics/NumberTheoreticFunctions.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/NumberTheoreticCompilationTest.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
81 changes: 81 additions & 0 deletions Sources/AngouriMath/Functions/Compilation/IntoFE/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,87 @@ private protected override void CompileNode(Compiler compiler)
}
}

// The number-theoretic functions, exact at a whole argument and NaN at any other.
// https://github.com/asc-community/AngouriMath/issues/2195
public partial record Mobiusf
{
private protected override bool CompilesItself => true;

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

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

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

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

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

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

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

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

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

public partial record DivisorSigmaf
{
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_DIVISOR_SIGMA));
}
}

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

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

public partial record Maxf
{
private protected override bool CompilesItself => true;
Expand Down
28 changes: 28 additions & 0 deletions Sources/AngouriMath/Functions/Compilation/IntoFE/FastExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ internal enum InstructionType
CALL_NOT,
CALL_DOUBLE_FACTORIAL,
CALL_CATALAN_NUMBER,
CALL_MOBIUS,
CALL_PRIME_NU,
CALL_PRIME_OMEGA,
CALL_PRIME,
CALL_PRIME_PI,

// 2-arg functions
CALL_SUM = 100,
Expand Down Expand Up @@ -85,6 +90,8 @@ internal enum InstructionType
CALL_LAMBERTW,
CALL_POLYGAMMA,
CALL_HARMONIC_NUMBER,
CALL_DIVISOR_SIGMA,
CALL_VALUATION,

// 3-arg: a value where its predicate holds, and the one below it elsewhere.
CALL_SELECT = 150,
Expand Down Expand Up @@ -368,6 +375,27 @@ public System.Numerics.Complex Substitute(params System.Numerics.Complex[] value
case InstructionType.CALL_HARMONIC_NUMBER:
stack.Push(AngouriMath.Numerics.PolygammaFunction.HarmonicNumber(stack.Pop(), stack.Pop()));
break;
case InstructionType.CALL_MOBIUS:
stack.Push(AngouriMath.Numerics.NumberTheoreticFunctions.Mobius(stack.Pop()));
break;
case InstructionType.CALL_PRIME_NU:
stack.Push(AngouriMath.Numerics.NumberTheoreticFunctions.PrimeNu(stack.Pop()));
break;
case InstructionType.CALL_PRIME_OMEGA:
stack.Push(AngouriMath.Numerics.NumberTheoreticFunctions.PrimeOmega(stack.Pop()));
break;
case InstructionType.CALL_PRIME:
stack.Push(AngouriMath.Numerics.NumberTheoreticFunctions.Prime(stack.Pop()));
break;
case InstructionType.CALL_PRIME_PI:
stack.Push(AngouriMath.Numerics.NumberTheoreticFunctions.PrimePi(stack.Pop()));
break;
case InstructionType.CALL_DIVISOR_SIGMA:
stack.Push(AngouriMath.Numerics.NumberTheoreticFunctions.DivisorSigma(stack.Pop(), stack.Pop()));
break;
case InstructionType.CALL_VALUATION:
stack.Push(AngouriMath.Numerics.NumberTheoreticFunctions.Valuation(stack.Pop(), stack.Pop()));
break;
case InstructionType.CALL_CATALAN_NUMBER:
stack.Push(AngouriMath.Numerics.CombinatorialFunctions.CatalanNumber(stack.Pop()));
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ Chif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Chi",
Factorialf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Factorial", 1, newE.Type), newE),
DoubleFactorialf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("DoubleFactorial", 1, newE.Type), newE),
CatalanNumberf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("CatalanNumber", 1, newE.Type), newE),
// The number-theoretic functions, exact at a whole argument and NaN at any other.
// https://github.com/asc-community/AngouriMath/issues/2195
Mobiusf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Mobius", 1, newE.Type), newE),
PrimeNuf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("PrimeNu", 1, newE.Type), newE),
PrimeOmegaf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("PrimeOmega", 1, newE.Type), newE),
Primef when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Prime", 1, newE.Type), newE),
PrimePif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("PrimePi", 1, newE.Type), newE),
Phif => Expression.Call(GetDef("Phi", 1, e.Type), e),

// The conjugate, the argument and the parts, widened to double as the special
Expand Down Expand Up @@ -249,6 +256,10 @@ Polygammaf when ShouldBeAtLeastDouble(left) is var newLeft && ShouldBeAtLeastDou
=> 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),
DivisorSigmaf when ShouldBeAtLeastDouble(left) is var newLeft && ShouldBeAtLeastDouble(right) is var newRight
=> Expression.Call(GetDef("DivisorSigma", 2, newLeft.Type), newLeft, newRight),
Valuationf when ShouldBeAtLeastDouble(left) is var newLeft && ShouldBeAtLeastDouble(right) is var newRight
=> Expression.Call(GetDef("Valuation", 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 @@ -356,6 +356,23 @@ public static System.Numerics.Complex Round(System.Numerics.Complex a)
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);

// The functions of a factorisation, the valuation, the n-th prime and the prime-counting function, by the
// interpreter's routines. https://github.com/asc-community/AngouriMath/issues/2195
public static System.Numerics.Complex Mobius(System.Numerics.Complex a) => AngouriMath.Numerics.NumberTheoreticFunctions.Mobius(a);
public static double Mobius(double a) => AngouriMath.Numerics.NumberTheoreticFunctions.Mobius(a);
public static System.Numerics.Complex PrimeNu(System.Numerics.Complex a) => AngouriMath.Numerics.NumberTheoreticFunctions.PrimeNu(a);
public static double PrimeNu(double a) => AngouriMath.Numerics.NumberTheoreticFunctions.PrimeNu(a);
public static System.Numerics.Complex PrimeOmega(System.Numerics.Complex a) => AngouriMath.Numerics.NumberTheoreticFunctions.PrimeOmega(a);
public static double PrimeOmega(double a) => AngouriMath.Numerics.NumberTheoreticFunctions.PrimeOmega(a);
public static System.Numerics.Complex Prime(System.Numerics.Complex a) => AngouriMath.Numerics.NumberTheoreticFunctions.Prime(a);
public static double Prime(double a) => AngouriMath.Numerics.NumberTheoreticFunctions.Prime(a);
public static System.Numerics.Complex PrimePi(System.Numerics.Complex a) => AngouriMath.Numerics.NumberTheoreticFunctions.PrimePi(a);
public static double PrimePi(double a) => AngouriMath.Numerics.NumberTheoreticFunctions.PrimePi(a);
public static System.Numerics.Complex DivisorSigma(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.NumberTheoreticFunctions.DivisorSigma(a, b);
public static double DivisorSigma(double a, double b) => AngouriMath.Numerics.NumberTheoreticFunctions.DivisorSigma(a, b);
public static System.Numerics.Complex Valuation(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.NumberTheoreticFunctions.Valuation(a, b);
public static double Valuation(double a, double b) => AngouriMath.Numerics.NumberTheoreticFunctions.Valuation(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 @@ -556,6 +573,20 @@ public static bool IsNaN(System.Numerics.Complex a)
{ ("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)) },
{ ("Mobius", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Mobius(a)) },
{ ("Mobius", 1, typeof(double)), Def<double>(a => Mobius(a)) },
{ ("PrimeNu", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => PrimeNu(a)) },
{ ("PrimeNu", 1, typeof(double)), Def<double>(a => PrimeNu(a)) },
{ ("PrimeOmega", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => PrimeOmega(a)) },
{ ("PrimeOmega", 1, typeof(double)), Def<double>(a => PrimeOmega(a)) },
{ ("Prime", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Prime(a)) },
{ ("Prime", 1, typeof(double)), Def<double>(a => Prime(a)) },
{ ("PrimePi", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => PrimePi(a)) },
{ ("PrimePi", 1, typeof(double)), Def<double>(a => PrimePi(a)) },
{ ("DivisorSigma", 2, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>((a, b) => DivisorSigma(a, b)) },
{ ("DivisorSigma", 2, typeof(double)), Def<double>((a, b) => DivisorSigma(a, b)) },
{ ("Valuation", 2, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>((a, b) => Valuation(a, b)) },
{ ("Valuation", 2, typeof(double)), Def<double>((a, b) => Valuation(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 @@ -19,6 +19,9 @@
// https://github.com/asc-community/AngouriMath/issues/2195
var combinatorial = new[]{ "DoubleFactorial", "CatalanNumber" };
var combinatorialBinary = new[]{ "Binomial", "FallingFactorial", "RisingFactorial" };
// The number-theoretic functions, exact at a whole argument and NaN at any other.
var numberTheoretic = new[]{ "Mobius", "PrimeNu", "PrimeOmega", "Prime", "PrimePi" };
var numberTheoreticBinary = new[]{ "DivisorSigma", "Valuation" };
var types = new[]{ "System.Numerics.Complex", "double", "float", "long", "int", "BigInteger" };
#>
//
Expand Down Expand Up @@ -244,6 +247,17 @@ namespace AngouriMath.Core.Compilation.IntoLinq
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);

// The functions of a factorisation, the valuation, the n-th prime and the prime-counting function, by the
// interpreter's routines. https://github.com/asc-community/AngouriMath/issues/2195
<# foreach (var name in numberTheoretic) { #>
public static System.Numerics.Complex <#= name #>(System.Numerics.Complex a) => AngouriMath.Numerics.NumberTheoreticFunctions.<#= name #>(a);
public static double <#= name #>(double a) => AngouriMath.Numerics.NumberTheoreticFunctions.<#= name #>(a);
<# } #>
<# foreach (var name in numberTheoreticBinary) { #>
public static System.Numerics.Complex <#= name #>(System.Numerics.Complex a, System.Numerics.Complex b) => AngouriMath.Numerics.NumberTheoreticFunctions.<#= name #>(a, b);
public static double <#= name #>(double a, double b) => AngouriMath.Numerics.NumberTheoreticFunctions.<#= name #>(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 @@ -302,6 +316,16 @@ namespace AngouriMath.Core.Compilation.IntoLinq
{ ("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)) },
<# } #>
<# foreach (var name in numberTheoretic) { #>
<# foreach (var type in new[]{ "System.Numerics.Complex", "double" }) { #>
{ ("<#= name #>", 1, typeof(<#= type #>)), Def<<#= type #>>(a => <#= name #>(a)) },
<# } #>
<# } #>
<# foreach (var name in numberTheoreticBinary) { #>
<# foreach (var type in new[]{ "System.Numerics.Complex", "double" }) { #>
{ ("<#= name #>", 2, typeof(<#= type #>)), Def<<#= type #>>((a, b) => <#= name #>(a, b)) },
<# } #>
<# } #>
};

Expand Down
Loading
Loading