diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 0ab69148c..430aa694f 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -2917,6 +2917,20 @@ since they are these exponentials | `"(p + q*x)^2*f^(a + b*x + c*x^2)".Integrate("x")` | `integral((p + q * x) ^ 2 * f ^ (a + b * x + c * x ^ 2), x)` | the antiderivative | | `"x^2*sinh(a + b*x + c*x^2)".Integrate("x")` | `integral(x ^ 2 * (e ^ (a + b * x + c * x ^ 2) - e ^ (-(a + b * x + c * x ^ 2))) / 2, x)` | the antiderivative | +### A Gaussian below the bar is read as the exponential of its negated exponent + +`e^(-x^2)/x^2` was integrated by the Gaussian's moments, and `1/(e^(x^2) x^2)`, the same function, +was not: the rule for the moments took the exponential from above the bar only. By parts writes +the factor beside `erf(b x)` in `erf(b x)/(e^(b^2 x^2) x^2)` the second way, and that integral was +declined for want of it ([#1501](https://github.com/asc-community/AngouriMath/issues/1501)). Both +columns measured on a build, `v2.5.0` against this change; `erf` had no reading in 2.5.0, which its +own entry records. + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"1/(e^(x^2)*x^2)".Integrate("x")` | `integral(1 / (e ^ x ^ 2 * x ^ 2), x)` | `-1 / x * e ^ (-x ^ 2) + (-2) * pi ^ (1/2) / 2 * erf(x) + C` | +| `"erf(b*x)/(e^(b^2*x^2)*x^2)".Integrate("x")` | `UnrecognizedFunctionParseException`: there is no function `erf` | an antiderivative in `erf` and `Ei(-2 b^2 x^2)` | + ### An exponential of a polynomial beside the polynomial's derivative is integrated `e^(a + b x + c x^2) (b + 2 c x) sqrt(a + b x + c x^2)` was left unintegrated. `G^P k P' f(P)`, with diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IntegralPatterns.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IntegralPatterns.cs index cf2e5a968..b4424296e 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IntegralPatterns.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IntegralPatterns.cs @@ -232,9 +232,13 @@ private static bool TakeMomentFactor(Entity factor, bool inverted, Entity.Variab power = inverted ? -n.EInteger.ToInt32Checked() : n.EInteger.ToInt32Checked(); return true; } - if (!inverted && gaussian is null && factor is Entity.Powf(var @base, _) exponential && !@base.ContainsNode(x)) + // Below the bar too, as the exponential of the negated exponent: `1/(e^(b^2 x^2) x^2)` is + // `e^(-b^2 x^2)/x^2`, and it is how by parts writes the factor beside `erf(b x)` in + // `erf(b x)/(e^(b^2 x^2) x^2)`, which was declined for want of its integral. + // https://github.com/asc-community/AngouriMath/issues/1501 + if (gaussian is null && factor is Entity.Powf(var @base, var exponent) exponential && !@base.ContainsNode(x)) { - gaussian = exponential; + gaussian = inverted ? new Entity.Powf(@base, -exponent) : exponential; return true; } // A sum, or a whole power of one, taken as it is: read as a polynomial only once a diff --git a/Sources/Tests/UnitTests/Calculus/GaussianIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/GaussianIntegralTest.cs index ff5dac019..3cfe8110f 100644 --- a/Sources/Tests/UnitTests/Calculus/GaussianIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/GaussianIntegralTest.cs @@ -103,6 +103,8 @@ public void ASymbolicGaussianIsUnconditional() [InlineData("e^(-x^2)/x^2")] [InlineData("e^(x^2)/x^4")] [InlineData("3*x^6*e^(-2*x^2)/5")] + [InlineData("1/(e^(x^2)*x^2)")] + [InlineData("1/(e^(2*x^2)*x^4)")] public void TheGaussianBesideAnEvenPower(string integrand) => DifferentiatesBack(integrand); ///