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: 11 additions & 4 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2316,9 +2316,9 @@ resort, Newton's method, compiles the expression and its derivative. They compil
not ordered;
- `max` and `min` differentiate where their arguments are real, as `|f|` does.

The search still declines what has no compiled form, so `erf(x) = x/2 + 1/7` is left unsolved. It
now also declines a set of roots that are not isolated: where the equation holds midway between two
of them, the points are samples of a continuum and not the set
The search still declines what has no compiled form, so `binomial(x, 3/2) = x/2` is left unsolved.
It now also declines a set of roots that are not isolated: where the equation holds midway between
two of them, the points are samples of a continuum and not the set
([#1603](https://github.com/asc-community/AngouriMath/issues/1603),
[#1420](https://github.com/asc-community/AngouriMath/issues/1420)).

Expand Down Expand Up @@ -2387,7 +2387,10 @@ e^(-t^2) dt`, its complement `erfc(z) = 1 - erf(z)` and the imaginary error func
`erfi(z) = -i erf(i z)` are nodes (`MathS.Erf`, `MathS.Erfc`, `MathS.Erfi`), the first of #1501's
special functions. Each is differentiated, printed in LaTeX as `\operatorname{erf}` and so on, and
evaluated to the working precision anywhere in the complex plane (`Entity.Number.Erf`, `Erfc`,
`Erfi`). An equation in one of them is left unsolved rather than answered with no roots. `erf`
`Erfi`). They compile, through `Compile` and `Compile<TIn, TOut>`, in double precision
([#1607](https://github.com/asc-community/AngouriMath/issues/1607)). So an equation the solver's
numerical search reaches, `erf(x) = x/2 + 1/7`, is answered with the roots it finds, while one that
isolates `erf`, `erf(x) = 1/2`, is left unsolved rather than answered with no roots. `erf`
was refused by name, but `erfc` and `erfi` were not, so each was read as a product with an
undeclared variable.

Expand All @@ -2398,6 +2401,8 @@ undeclared variable.
| `"erfi(x)"` | `erfi * x` | `erfi(x)` |
| `"erfc(1)".Simplify()` | `erfc` | `erfc(1)`, and `0.157299207050285鈥 evaluated |
| `"erf(x)".Differentiate("x")` | `UnrecognizedFunctionParseException` | `2 / sqrt(pi) * e ^ (-x ^ 2)` |
| `"erf(x)".Compile("x")`, and `erfc`, `erfi` | `UnrecognizedFunctionParseException`; for `erfc` and `erfi`, `UncompilableNodeException`: not among the variables | compiled |
| `"erf(x) = x/2 + 1/7".ToEntity().Solve("x")` | `UnrecognizedFunctionParseException` | its roots near `-2.283`, `0.235` and `1.679`, and more off the real line |

### `Ei` and `li` are functions

Expand All @@ -2417,6 +2422,7 @@ with an undeclared variable
| `"li(2)".Simplify()` | `2 * li` | `li(2)`, and `1.045163780117492鈥 evaluated |
| `"Ei(1)".Simplify()` | `Ei` | `Ei(1)`, and `1.895117816355936鈥 evaluated |
| `"Ei(x)".Differentiate("x")` | `Ei` | `e ^ x / x` |
| `"Ei(x)".Compile("x")`, and `li` | `UncompilableNodeException`: `Ei` is not among the variables | compiled ([#1607](https://github.com/asc-community/AngouriMath/issues/1607)) |

### The exponential and logarithmic integrals are integrated to

Expand Down Expand Up @@ -2455,6 +2461,7 @@ was refused, so each was read as a product with an undeclared variable
| `"Ci(2)".Simplify()` | `2 * Ci` | `Ci(2)`, and `0.4229808287748649鈥 evaluated |
| `"Chi(1)".Simplify()` | `Chi` | `Chi(1)`, and `0.8378669409802082鈥 evaluated |
| `"Si(x)".Differentiate("x")` | `Si` | `sin(x) / x` |
| `"Si(x)".Compile("x")`, and `Ci`, `Shi`, `Chi` | `UncompilableNodeException`: `Si` is not among the variables | compiled ([#1607](https://github.com/asc-community/AngouriMath/issues/1607)) |

### A quadratic below a sine or a cosine is split over its two roots

Expand Down
3 changes: 3 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[AngouriMath/Core/Entity/Continuous/Number/ErrorFunctions.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/SpecialFunctions.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/Core/Entity/Continuous/Entity.Continuous.ErrorFunctions.Classes.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
101 changes: 101 additions & 0 deletions Sources/AngouriMath/Functions/Compilation/IntoFE/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,107 @@ private protected override void CompileNode(Compiler compiler)
compiler.Instructions.Add(new(InstructionType.CALL_PHI));
}
}

// The special functions, in double precision as the kernels define them.
// https://github.com/asc-community/AngouriMath/issues/1607
public partial record Erff
{
private protected override bool CompilesItself => true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Expand Down
38 changes: 38 additions & 0 deletions Sources/AngouriMath/Functions/Compilation/IntoFE/FastExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ internal enum InstructionType
CALL_FLOOR,
CALL_CEIL,
CALL_ROUND,
CALL_ERF,
CALL_ERFC,
CALL_ERFI,
CALL_EI,
CALL_LI,
CALL_SI,
CALL_CI,
CALL_SHI,
CALL_CHI,

// 2-arg functions
CALL_SUM = 100,
Expand Down Expand Up @@ -219,6 +228,35 @@ public System.Numerics.Complex Substitute(params System.Numerics.Complex[] value
case InstructionType.CALL_ARCCOSECANT:
stack.Push(Core.Compilation.ComplexBranches.Arccosecant(stack.Pop()));
break;
// In double precision, as the kernels define them.
// https://github.com/asc-community/AngouriMath/issues/1607
case InstructionType.CALL_ERF:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Erf(stack.Pop()));
break;
case InstructionType.CALL_ERFC:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Erfc(stack.Pop()));
break;
case InstructionType.CALL_ERFI:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Erfi(stack.Pop()));
break;
case InstructionType.CALL_EI:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Ei(stack.Pop()));
break;
case InstructionType.CALL_LI:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Li(stack.Pop()));
break;
case InstructionType.CALL_SI:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Si(stack.Pop()));
break;
case InstructionType.CALL_CI:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Ci(stack.Pop()));
break;
case InstructionType.CALL_SHI:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Shi(stack.Pop()));
break;
case InstructionType.CALL_CHI:
stack.Push(AngouriMath.Numerics.SpecialFunctions.Chi(stack.Pop()));
break;
case InstructionType.CALL_FACTORIAL:
// https://stackoverflow.com/a/15454784/5429648
const int g = 7;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ Arccosecantf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef
Floorf => Expression.Call(GetDef("Floor", 1, e.Type), e),
Ceilf => Expression.Call(GetDef("Ceil", 1, e.Type), e),
Roundf => Expression.Call(GetDef("Round", 1, e.Type), e),

// The special functions, widened to double first as the trigonometry is.
// https://github.com/asc-community/AngouriMath/issues/1607
Erff when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Erf", 1, newE.Type), newE),
Erfcf when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Erfc", 1, newE.Type), newE),
Erfif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Erfi", 1, newE.Type), newE),
Eif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Ei", 1, newE.Type), newE),
Lif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Li", 1, newE.Type), newE),
Sif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Si", 1, newE.Type), newE),
Cif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Ci", 1, newE.Type), newE),
Shif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Shi", 1, newE.Type), newE),
Chif when ShouldBeAtLeastDouble(e) is var newE => Expression.Call(GetDef("Chi", 1, newE.Type), newE),

Notf => Expression.Not(e),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,27 @@ public static System.Numerics.Complex Round(System.Numerics.Complex a)
public static int Min(int a, int b) => Math.Min(a, b);
public static BigInteger Min(BigInteger a, BigInteger b) => BigInteger.Min(a, b);

// The special functions, in double precision as the kernels define them.
// https://github.com/asc-community/AngouriMath/issues/1607
public static System.Numerics.Complex Erf(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Erf(a);
public static double Erf(double a) => AngouriMath.Numerics.SpecialFunctions.Erf(a);
public static System.Numerics.Complex Erfc(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Erfc(a);
public static double Erfc(double a) => AngouriMath.Numerics.SpecialFunctions.Erfc(a);
public static System.Numerics.Complex Erfi(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Erfi(a);
public static double Erfi(double a) => AngouriMath.Numerics.SpecialFunctions.Erfi(a);
public static System.Numerics.Complex Ei(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Ei(a);
public static double Ei(double a) => AngouriMath.Numerics.SpecialFunctions.Ei(a);
public static System.Numerics.Complex Li(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Li(a);
public static double Li(double a) => AngouriMath.Numerics.SpecialFunctions.Li(a);
public static System.Numerics.Complex Si(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Si(a);
public static double Si(double a) => AngouriMath.Numerics.SpecialFunctions.Si(a);
public static System.Numerics.Complex Ci(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Ci(a);
public static double Ci(double a) => AngouriMath.Numerics.SpecialFunctions.Ci(a);
public static System.Numerics.Complex Shi(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Shi(a);
public static double Shi(double a) => AngouriMath.Numerics.SpecialFunctions.Shi(a);
public static System.Numerics.Complex Chi(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.Chi(a);
public static double Chi(double a) => AngouriMath.Numerics.SpecialFunctions.Chi(a);

/// <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 @@ -438,6 +459,24 @@ public static bool IsNaN(System.Numerics.Complex a)
{ ("Round", 1, typeof(long)), Def<long>(a => Round(a)) },
{ ("Round", 1, typeof(int)), Def<int>(a => Round(a)) },
{ ("Round", 1, typeof(BigInteger)), Def<BigInteger>(a => Round(a)) },
{ ("Erf", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Erf(a)) },
{ ("Erf", 1, typeof(double)), Def<double>(a => Erf(a)) },
{ ("Erfc", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Erfc(a)) },
{ ("Erfc", 1, typeof(double)), Def<double>(a => Erfc(a)) },
{ ("Erfi", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Erfi(a)) },
{ ("Erfi", 1, typeof(double)), Def<double>(a => Erfi(a)) },
{ ("Ei", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Ei(a)) },
{ ("Ei", 1, typeof(double)), Def<double>(a => Ei(a)) },
{ ("Li", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Li(a)) },
{ ("Li", 1, typeof(double)), Def<double>(a => Li(a)) },
{ ("Si", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Si(a)) },
{ ("Si", 1, typeof(double)), Def<double>(a => Si(a)) },
{ ("Ci", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Ci(a)) },
{ ("Ci", 1, typeof(double)), Def<double>(a => Ci(a)) },
{ ("Shi", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Shi(a)) },
{ ("Shi", 1, typeof(double)), Def<double>(a => Shi(a)) },
{ ("Chi", 1, typeof(System.Numerics.Complex)), Def<System.Numerics.Complex>(a => Chi(a)) },
{ ("Chi", 1, typeof(double)), Def<double>(a => Chi(a)) },
};

// 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 @@ -9,6 +9,9 @@
"Cot", "Sec", "Csc", "Acot", "Asec", "Acsc",
"Abs", "Sgn", "Floor", "Ceil", "Round" };
var binary = new[]{ "Log", "Pow", "Max", "Min" };
// Defined for Complex and double alone: an integer or a float is widened to double first, as
// for the trigonometry.
var special = new[]{ "Erf", "Erfc", "Erfi", "Ei", "Li", "Si", "Ci", "Shi", "Chi" };
var types = new[]{ "System.Numerics.Complex", "double", "float", "long", "int", "BigInteger" };
#>
//
Expand Down Expand Up @@ -188,6 +191,13 @@ namespace AngouriMath.Core.Compilation.IntoLinq
public static int Min(int a, int b) => Math.Min(a, b);
public static BigInteger Min(BigInteger a, BigInteger b) => BigInteger.Min(a, b);

// The special functions, in double precision as the kernels define them.
// https://github.com/asc-community/AngouriMath/issues/1607
<# foreach (var name in special) { #>
public static System.Numerics.Complex <#= name #>(System.Numerics.Complex a) => AngouriMath.Numerics.SpecialFunctions.<#= name #>(a);
public static double <#= name #>(double a) => AngouriMath.Numerics.SpecialFunctions.<#= name #>(a);
<# } #>

/// <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 @@ -221,6 +231,11 @@ namespace AngouriMath.Core.Compilation.IntoLinq
<# foreach (var type in types) { #>
{ ("<#= name #>", 1, typeof(<#= type #>)), Def<<#= type #>>(a => <#= name #>(a)) },
<# } #>
<# } #>
<# foreach (var name in special) { #>
<# foreach (var type in new[]{ "System.Numerics.Complex", "double" }) { #>
{ ("<#= name #>", 1, typeof(<#= type #>)), Def<<#= type #>>(a => <#= name #>(a)) },
<# } #>
<# } #>
};

Expand Down
Loading
Loading