diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index a34469655..767f6bc37 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -396,6 +396,19 @@ in Rubi's 1.1.3.4 come out shorter as well, and those that took two seconds take | `"1/(x^8*(a + b*x^3)*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,217 characters | | `"1/(x^6*(a + b*x^4)*(c + d*x^4))".ToEntity().Integrate("x")` | `integral(...)` | 795 characters | +### A difference of two cubes is split over the cube roots of unity where its answer cannot be sampled + +**Answers where there were none.** `1/(a - b cosh(x)^3)` was declined, which Rubi's 6.2.7 has. Under `u = e^x` it is +`8 u^2/(8 a u^3 - b (u^2 + 1)^3)`, a difference of two cubes, which the rule for a sum of two cubes split correctly and +then refused: with the second cube negative, the real cube root makes all three quadratics complex at the sampled +values, and too few points could be compared. The answer is now refused only where it differs +([#718](https://github.com/asc-community/AngouriMath/issues/718)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"1/(a-b*cosh(x)^3)".ToEntity().Integrate("x")` | `integral(...)` | 666 characters | +| `"8*x^2/(8*a*x^3-b*(x^2+1)^3)".ToEntity().Integrate("x")` | `integral(...)` | 654 characters | + ### A negative power of an inverse function of `c + d x^2` is integrated in sine and cosine integrals **Answers where there were none.** `1/(a + b acos(1 + d x^2))` was declined, and so were seventeen more of Rubi's diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 1c6458f74..12b4ccf64 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -19676,7 +19676,11 @@ Piecewise piecewise when piecewise.Cases.Any() => piecewise.Cases.First().Expres foreach (var unity in unities) answer = answer + unity * each.Substitute(namedB, unity * root).Substitute(namedS, shift); answer = (constant / (3 * d6 * MathS.Pow(root, Number.Integer.Create(2))) * answer).InnerSimplified; - return Functions.PartialFractions.DerivativeHoldsAtSampledPoints(answer, expr, x) ? answer : null; + // Refused where it differs, not where it cannot be told: with `q < 0` the real cube root + // makes all three quadratics' coefficients complex at the pinned values, the intervals + // settle too few points, and `8 x^2/(8 a x^3 - b (x^2 + 1)^3)` -- `1/(a - b cosh(x)^3)` + // under `u = e^x` -- was declined where its `+ b` twin was answered. + return Functions.PartialFractions.DerivativeDiffersWhereReal(answer, expr, x) ? null : answer; } /// diff --git a/Sources/Tests/UnitTests/Calculus/ASumOfTwoCubesIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/ASumOfTwoCubesIntegralTest.cs index 4ef667494..5254c2e04 100644 --- a/Sources/Tests/UnitTests/Calculus/ASumOfTwoCubesIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/ASumOfTwoCubesIntegralTest.cs @@ -55,5 +55,18 @@ public void IsAnsweredAndDifferentiatesBack(string integrand) DifferentiatesBack(integrand, ("a", 2), ("b", 3), ("c", 5)); DifferentiatesBack(integrand, ("a", -1), ("b", 2), ("c", -3)); } + + // A difference of two cubes, the second cube's coefficient negative: `1/(a - b cosh(x)^3)` is + // `8 u^2/(8 a u^3 - b (u^2 + 1)^3)` under `u = e^x`. The real cube root makes all three + // quadratics complex at sampled values, and the answer was refused for want of points. + [Theory] + [InlineData("8*x^2/(8*a*x^3-b*(x^2+1)^3)")] + [InlineData("1/(a-b*cosh(x)^3)")] + [InlineData("x/(27*a^3+27*a^2*b*x^2-27*a^2*c*x^3+9*a*b^2*x^4+b^3*x^6)")] + public void ADifferenceIsAnsweredAndDifferentiatesBack(string integrand) + { + DifferentiatesBack(integrand, ("a", 2), ("b", 3), ("c", 5)); + DifferentiatesBack(integrand, ("a", -1), ("b", 2), ("c", -3)); + } } }