diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 85189f790..c953e08fc 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -435,6 +435,20 @@ by the linear's coefficients, `(b d + 2c d x)^9`, which ran past a minute | `"(b + 2*c*x)^9/(a + b*x + c*x^2)^3".ToEntity().Integrate("x")` | past a minute; 76,153 characters on the unreleased master | 607 characters | | `"(b*d + 2*c*d*x)^9/(a + b*x + c*x^2)^3".ToEntity().Integrate("x")` | past a minute | 611 characters | +### A square of a symbolic quadratic beside two linears is answered within the budget + +**Answers where there were none in time.** `1/((d + k x)(f + g x)(a + b x + c x^2)^2)` was declined by +2.5.0, and on the unreleased master it did not return in 300 seconds. The norm of the other factors +modulo the quadratic is a power of a product with a sum in it, and it was multiplied out term by term; +it is multiplied out as a polynomial in the symbols now. `1/((d + k x)^3 (a + b x + c x^2)^2)` gives the +same answer as on the unreleased master, in 1.4 seconds rather than 30 +([#718](https://github.com/asc-community/AngouriMath/issues/718)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"1/((d + k*x)*(f + g*x)*(a + b*x + c*x^2)^2)".ToEntity().Integrate("x")` | `integral(...)` | 24,143 characters | +| `"1/((d + k*x)^3*(a + b*x + c*x^2)^2)".ToEntity().Integrate("x")` | `integral(...)` | 9,593 characters | + ### A trinomial the numerator holds is divided out of a power of it **A shorter answer, where 2.5.0 had none.** `(d + g x + f x^2)(a + b x^2 + c x^4)/(a + b x^2 + c x^4)^4`, written diff --git a/Sources/AngouriMath/Functions/Algebra/Polynomials/PartialFractions.cs b/Sources/AngouriMath/Functions/Algebra/Polynomials/PartialFractions.cs index d02fb4980..7bebb4905 100644 --- a/Sources/AngouriMath/Functions/Algebra/Polynomials/PartialFractions.cs +++ b/Sources/AngouriMath/Functions/Algebra/Polynomials/PartialFractions.cs @@ -674,8 +674,11 @@ internal static Entity InLowestTermsOverTheSymbols(Entity constant) private static Entity ExpandedOverTheSymbols(Entity expr) { // Only where there is a product to multiply out: a sum or a quotient of sums already - // written term by term keeps the spelling every other step reads it in. - if (!expr.Nodes.Any(node => node is Powf(Sumf or Minusf, Integer { EInteger: var power }) && power.CompareTo(EInteger.One) > 0 + // written term by term keeps the spelling every other step reads it in. A power of a + // product with a sum in it is one: the norm a repeated quadratic's inverse takes + // beside `(d + e x)^3` is `(S c)^2` for a sum `S` of 28 terms, and its expansion + // took 27 of the 29 seconds of `1/((d + e x)^3 (a + b x + c x^2)^2)`. + if (!expr.Nodes.Any(node => node is Powf(var @base, Integer { EInteger: var power }) && power.CompareTo(EInteger.One) > 0 && @base.Nodes.Any(n => n is Sumf or Minusf) || node is Mulf(var left, var right) && left.Nodes.Any(n => n is Sumf or Minusf) && right.Nodes.Any(n => n is Sumf or Minusf))) return expr.Expand(); var variables = expr.Vars.OrderBy(v => v.Name, System.StringComparer.Ordinal).ToList(); diff --git a/Sources/Tests/UnitTests/Calculus/SymbolicFactorsPartialFractionsTest.cs b/Sources/Tests/UnitTests/Calculus/SymbolicFactorsPartialFractionsTest.cs index 1cd1e8316..438573ffc 100644 --- a/Sources/Tests/UnitTests/Calculus/SymbolicFactorsPartialFractionsTest.cs +++ b/Sources/Tests/UnitTests/Calculus/SymbolicFactorsPartialFractionsTest.cs @@ -321,6 +321,9 @@ public void APolynomialOverALinearBesideARadicalIsReduced(string integrand) /// iteration. 1/((a + b x)^2 (c + d x)^(3/2)) is, under u = sqrt(c + d x), /// 1/(u^2 (K + u^2)^2) with a symbolic K, and went to the Hermite reduction /// for a hundred kilobytes in thirty seconds; it is eight kilobytes in half a second now. + /// Beside a cube of a linear, the norm of the other factors' residue is a power of a + /// product with a sum in it, which is multiplied out as a polynomial: expanded term by + /// term it took 27 of the 29 seconds of 1/((d + e x)^3 (a + b x + c x^2)^2). /// [Theory] [InlineData("1/((a + b*x)^2*(c + d*x)^(3/2))", 10000)] @@ -328,6 +331,7 @@ public void APolynomialOverALinearBesideARadicalIsReduced(string integrand) [InlineData("1/(x^3*(a + b*x + c*x^2)^2)", 10000)] [InlineData("x/((a + b*x)*(c + x^2)^2)", 4000)] [InlineData("(A + B*x)/((a + b*x)*(1 + x^2)^3)", 4000)] + [InlineData("1/((d + B*x)^3*(a + b*x + c*x^2)^2)", 12000)] public void ARepeatedSymbolicQuadraticBesideALinear(string integrand, int atMost) { DifferentiatesBack(integrand, "x", ("a", 1.7), ("b", 2.3), ("c", 0.4), ("d", 1.1), ("A", 0.5), ("B", 1.3));