diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index e1e4d9104..b8658ec88 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -1433,13 +1433,17 @@ polynomial, is integrated now by the recurrence `int L1^m L2^n = L1^(m + 1) L2^(n + 1)/((m + 1) D) - (m + n + 2) d/((m + 1) D) int L1^(m + 1) L2^n`, `D = b c - a d`, down to `int L2^n/L1`, the polynomial written in powers of `L1` first. The answers are the same functions as master's where master gave one, written as powers of the two -linears ([#718](https://github.com/asc-community/AngouriMath/issues/718)). +linears ([#718](https://github.com/asc-community/AngouriMath/issues/718)). Beside a multiple of the +same linear, where `D` is zero only as a value -- `b a c - a b c` for `a + b x` beside +`c a + c b x` -- the recurrence is not taken: it divided by `D`, and the answer had no value anywhere +([#1776](https://github.com/asc-community/AngouriMath/issues/1776)). | Input | Was (2.5.0) | Now | |---|---|---| | `"1/((a + b*x)^4*sqrt(c + d*x))".ToEntity().Integrate("x")` | `integral(...)` | powers of `a/b + x` beside `sqrt(c + d x)`, and the arctangent or logarithm `1/((a + b x) sqrt(c + d x))` integrates to | | `"(p + q*x + r*x^2 + s*x^3)/((a + b*x)^5*sqrt(c + d*x))".ToEntity().Integrate("x")` | `integral(...)` | the same, term by term | | `"x/((a + b*x)^4*sqrt(c + d*x))".ToEntity().Integrate("x")` | `integral(...)` | the same | +| `"(a + b*x)^(-3)/sqrt(c*a + c*b*x)".ToEntity().Integrate("x")` | `integral(...)` | `-2/(5 b) (a + b x)^(-2) (c a + c b x)^(-1/2)` | ### A polynomial over a power of a linear beside the root of a quadratic is integrated diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 79b44054b..0e14dbbad 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -10117,8 +10117,11 @@ void Gather(Entity node, int times) return null; if (!TreeAnalyzer.TryGetPolyLinear(first, x, out var b, out var a) || !TreeAnalyzer.TryGetPolyLinear(second, x, out var d, out var c)) return null; + // Zero as a value, not only as written: for `a + b x` beside `c a + c b x` it is + // `b a c - a b c`, and the recurrence divided by it -- an answer with no value anywhere. + // https://github.com/asc-community/AngouriMath/issues/1776 var determinant = (b * c - a * d).InnerSimplified; - if (determinant.Evaled is Number.Complex { IsZero: true }) + if (Functions.PartialFractions.IsZeroAsAValue(determinant)) return null; // The polynomial in powers of the first linear: x = (t - a)/b. var t = Variable.CreateUnique(expr, "t_linear"); diff --git a/Sources/Tests/UnitTests/Calculus/LinearPowerRecurrenceIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/LinearPowerRecurrenceIntegralTest.cs index 0f3b70e78..3a331febc 100644 --- a/Sources/Tests/UnitTests/Calculus/LinearPowerRecurrenceIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/LinearPowerRecurrenceIntegralTest.cs @@ -27,6 +27,22 @@ public sealed class LinearPowerRecurrenceIntegralTest [InlineData("1/(x^3*(c + d*x)^(5/2))")] [InlineData("x/((a + b*x)^4*sqrt(c + d*x))")] public void ByTheRecurrence(string integrand) + => DifferentiatesBack(integrand, new[] { -2.4, -1.5, 0.3, 0.8, 1.5, 2.4 }); + + /// + /// Beside a root of a multiple of the same linear, where the determinant the recurrence + /// divides by is zero only as a value, b a c - a b c: it was divided by, and the + /// answer had no value anywhere. + /// #1776 + /// + [Theory] + [InlineData("(a + b*x)^(-3)/sqrt(c*a + c*b*x)")] + [InlineData("1/(c*(a + b*x)^3)^(3/2)")] + [InlineData("1/(c*(a + b*x)^3)^(5/2)")] + public void BesideAMultipleOfTheSameLinear(string integrand) + => DifferentiatesBack(integrand, new[] { -1.2, -0.6, 0.3, 0.8, 1.5, 2.4 }); + + private static void DifferentiatesBack(string integrand, double[] points) { var integral = integrand.ToEntity().Integrate("x"); Assert.DoesNotContain("integral(", integral.Stringize()); @@ -35,7 +51,7 @@ Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.9).Substitut .Substitute("s", 0.6); var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x"); var original = Pinned(integrand.ToEntity()); - foreach (var at in new[] { -2.4, -1.5, 0.3, 0.8, 1.5, 2.4 }) + foreach (var at in points) { var want = original.Substitute("x", at).EvalNumerical(); var got = derivative.Substitute("x", at).EvalNumerical();