From 13eb63d15801199469dc0618a6b8de0d96acb6b1 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sat, 3 Oct 2026 13:27:14 +0000 Subject: [PATCH] The Hermite reduction's system is solved in one row order whatever the spelling The rational part of a Hermite reduction is one linear system, and its rows were the powers of x in the order the coefficient dictionaries met them, which follows how the denominator's factors are written. With symbols in the coefficients the elimination's pivots followed that order: x/((1 + x^2)^3 (2 a x + b (x^2 + 1))) solved to coefficients of the thirty-sixth degree in the symbols that nothing reduced, and declining their logarithmic part took 40 s before the answer, where with (x^2 + 1)^3 written the whole took 1 s. The rows are ordered by their power of x; both spellings take half a second. Part of #718. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 15 +++++++++++++++ .../Integration/IndefiniteIntegralSolver.cs | 7 ++++++- ...RationalFactorsBesideASymbolicQuadraticTest.cs | 13 +++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 8c5dd2952..edc8fff58 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -295,6 +295,21 @@ power up each step, and what reaches the first power is integrated once over the | `"1/(a + b*x^2 + c*x^4)^3".ToEntity().Integrate("x")` | `integral(...)` | the same | | `"x/(a + b*x^3 + c*x^6)^2".ToEntity().Integrate("x")` | `integral(...)` | a polynomial over `a + b x^3 + c x^6`, and the integral of a polynomial over it | +### The Hermite reduction's system is solved in one order whatever the spelling + +**Faster, and not a different value.** The reduction of a rational integrand with a repeated factor +below the bar solves one linear system for the rational part, and took its rows in the order the +powers of `x` were met, which follows how the factors are written. With symbols in the coefficients +the elimination's pivots followed that order, and in one order the solution came out as quotients of +polynomials of the thirty-sixth degree in the symbols that nothing reduced: +`x/((1 + x^2)^3 (2 a x + b (x^2 + 1)))` took 42 s, and with `(x^2 + 1)^3` below the bar 1 s. The rows +are ordered by their power of `x` now. Where the order mattered, the antiderivative's coefficients can +come out reduced where they were not. + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"x/((1 + x^2)^3*(2*a*x + b*(x^2 + 1)))".ToEntity().Integrate("x")` | `integral(...)` | the antiderivative, in about half a second, as with `(x^2 + 1)^3` | + ### A symbolic parameter no longer stops a rational integrand being integrated `1/(8 + x^3)` and `1/(16 - x^4)` are answered at once. `1/(a^3 + x^3)` and `1/(a^4 - x^4)` were not, diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 99a46ed02..bffae95f3 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -12615,7 +12615,12 @@ private static Entity SquarefreePartAsWritten(Entity denominator, Entity.Variabl ? PolynomialProduct(PolynomialProduct(abovePoly, dSquared), qSquared) : PolynomialProduct(PolynomialProduct(abovePoly, dSquared), squarefreePoly); - var powers = columns.SelectMany(c => c.Keys).Concat(targetRead.Keys).Distinct().ToList(); + // The rows by their power of x, not in the order the dictionaries met them: that order + // is the spelling's, and the elimination's pivots follow it. `(1 + x^2)^3` below the bar + // where `(x^2 + 1)^3` is written left the solution in coefficients of the thirty-sixth + // degree in the symbols that nothing cancelled, and the logarithmic part they made was + // forty seconds of declining; in the one order both are under a second. + var powers = columns.SelectMany(c => c.Keys).Concat(targetRead.Keys).Distinct().OrderBy(power => power).ToList(); var width = columns.Count; var matrix = new Entity[powers.Count][]; var rhs = new Entity[powers.Count]; diff --git a/Sources/Tests/UnitTests/Calculus/RationalFactorsBesideASymbolicQuadraticTest.cs b/Sources/Tests/UnitTests/Calculus/RationalFactorsBesideASymbolicQuadraticTest.cs index f43db2ae2..a6fd0788b 100644 --- a/Sources/Tests/UnitTests/Calculus/RationalFactorsBesideASymbolicQuadraticTest.cs +++ b/Sources/Tests/UnitTests/Calculus/RationalFactorsBesideASymbolicQuadraticTest.cs @@ -124,5 +124,18 @@ private static void AnswersAndDifferentiatesBack(string integrand) [InlineData("tan(x)^4/(a+b*csc(x))")] [InlineData("sin(x)^2/(a+b*cos(x))")] public void TheNeighboursStayAnswered(string integrand) => AnswersAndDifferentiatesBack(integrand); + + /// + /// The same integrand with `1 + x^2` written either way round. The Hermite reduction's + /// system took its rows in the order its dictionaries met the powers, which is the + /// spelling's, and with `(1 + x^2)^3` below the bar the solution came out in coefficients + /// of the thirty-sixth degree in the symbols that nothing cancelled: forty seconds of + /// declining their logarithmic part before the answer, where `(x^2 + 1)^3` took one. + /// + [Theory] + [InlineData("x/((1+x^2)^3*(2*a*x+b*(x^2+1)))")] + [InlineData("x/((x^2+1)^3*(2*a*x+b*(x^2+1)))")] + [InlineData("4*x*(1-x^2)^2/((1+x^2)^3*(2*a*x+b*(1+x^2)))")] + public void EitherSpellingOfOnePlusTheSquare(string integrand) => AnswersAndDifferentiatesBack(integrand); } }