diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 8bbc87289..b73c79b1d 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -838,6 +838,21 @@ but `sqrt(q)^2 = q` ([#1598](https://github.com/asc-community/AngouriMath/issues
| `"1/sqrt(-x^2 + i)".Integrate("x")` | `-arcsin(-2x/sqrt(4i)) + C` | `ln(-2x + 2i sqrt(-x^2 + i))/i + C`, an antiderivative as before, in the logarithm |
| `"1/(sqrt(x)*sqrt(1 + i*x))".Integrate("x")`, and Rubi 4.3.2.1's `sqrt(tan(c + d x))/(a + i a tan(c + d x))^(5/2)` | `integral(...)` | the antiderivative |
+### A quotient by the square of a base is integrated by parts against the base's reciprocal
+
+**Answers where there were none.** `x^2/(a x cos(a x) - sin(a x))^2` was declined, with the rest of
+Rubi's 4.7.7 over the square of `a x cos(a x) - sin(a x)` or `cos(a x) + a x sin(a x)`. A quotient
+`N/(M v^2)` by the square of a base with a function of `x` in it is `g v'/v^2` with `g = N/(M v')`, and
+`v'/v^2` is the derivative of `-1/v`: its integral is `-g/v` plus the integral of `g'/v`, taken where
+the base's derivative is one term and `v` cancels from `g'/v`
+([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"x^2/(a*x*cos(a*x) - sin(a*x))^2".ToEntity().Integrate("x")` | `integral(...)` | `x/(a^2 sin(a x) (a x cos(a x) - sin(a x))) - cot(a x)/a^3` |
+| `"sin(a*x)^2/(a*x*cos(a*x) - sin(a*x))^2".ToEntity().Integrate("x")` | `integral(...)` | a quotient by `a x cos(a x) - sin(a x)` and `1/(a^2 x)` |
+| `"sin(a*x)^3/(x*(a*x*cos(a*x) - sin(a*x))^2)".ToEntity().Integrate("x")` | `integral(...)` | the same with the sine integral `Si(a x)` |
+
### Trigonometric functions of multiples of one linear argument are written in it
`csc(a + b x) csc(2a + 2b x)^2` was left unevaluated, and `csc(1 + x) csc(2 + 2x)^2` ran twenty
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 4dfdb9821..fd17457b1 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -367,6 +367,81 @@ private static bool IsADerivativeOfAFactorBelowTheBar(Entity expr, Entity.Variab
return Integration.ComputeAsTheSameQuestion(written, x, integrateByParts);
}
+ ///
+ /// A quotient by the square of a base, by parts against the base's reciprocal, where the
+ /// base's derivative makes the rest exact: N/(M v^2) is g v'/v^2 with
+ /// g = N/(M v'), and v'/v^2 is the derivative of -1/v, so the integral
+ /// is -g/v plus the integral of g'/v; taken only where v cancels from
+ /// that, with the functions of in it taken for indeterminates.
+ ///
+ ///
+ /// x^2/(a x cos(a x) - sin(a x))^2 was declined, with the rest of Rubi's 4.7.7 by the
+ /// square of a x cos(a x) - sin(a x) or cos(a x) + a x sin(a x): the base's
+ /// derivative is -a^2 x sin(a x), so g is -x csc(a x)/a^2, and
+ /// g' is a^2 v/(a^2 sin(a x))^2, whose integral is -cot(a x)/a^3. Only
+ /// for a base with a function of in it that is not a polynomial, since
+ /// a quotient of polynomials is the partial fractions', and only where v cancels,
+ /// since otherwise the remainder is the harder question.
+ /// https://github.com/asc-community/AngouriMath/issues/718
+ ///
+ internal static Entity? SolveByPartsAgainstTheReciprocalOfASquaredBase(Entity expr, Entity.Variable x)
+ {
+ if (!TryReadAsQuotient(expr, out var numerator, out var denominator) || !denominator.ContainsNode(x))
+ return null;
+ Entity? squared = null;
+ Entity rest = Number.Integer.One;
+ foreach (var factor in Mulf.LinearChildren(denominator))
+ if (squared is null && factor is Powf(var @base, Number.Integer { EInteger: var power }) && power.Equals(EInteger.FromInt32(2))
+ && @base is Sumf or Minusf && @base.ContainsNode(x)
+ && @base.Nodes.Any(node => node.ContainsNode(x) && IsAFunctionOfTheVariable(node))
+ // The variable outside the functions as well, as in `a x cos(a x) - sin(a x)`: a
+ // base that is a function of `sin(x)` alone, `(a + b sin(x))^2`, is the
+ // substitutions' and the reductions', and was answered in a second where this
+ // ran past the budget.
+ && @base.Replace(node => IsAFunctionOfTheVariable(node) ? Number.Integer.One : node).ContainsNode(x))
+ squared = @base;
+ else
+ rest = rest * factor;
+ if (squared is null)
+ return null;
+ // A power of x every term of the base has goes to the rest: `x^2 v^2` arrives as
+ // `(a x^2 cos(a x) - x sin(a x))^2`, the square of `x v`.
+ var lowest = Sumf.LinearChildren(squared).Select(term => Mulf.LinearChildren(term)
+ .Select(factor => factor == x ? 1 : factor is Powf(var b, Number.Integer { EInteger: var n }) && b == x && n.CanFitInInt32() ? n.ToInt32Unchecked() : 0)
+ .Sum()).Min();
+ if (lowest > 0)
+ {
+ squared = (squared / MathS.Pow(x, lowest)).Expand().InnerSimplified;
+ rest = rest * MathS.Pow(x, 2 * lowest);
+ }
+ // Expanded, since the derivative of `a x cos(a x)` and of `sin(a x)` each have an
+ // `a cos(a x)`, which cancel only once multiplied out.
+ var derivative = squared.Differentiate(x).Expand().InnerSimplified;
+ // A derivative of one term, so that what it leaves below the bar of the remainder is
+ // no new square of a sum to take apart the same way.
+ if (TreeAnalyzer.IsZero(derivative) || derivative is Sumf or Minusf)
+ return null;
+ // The ring's answer first, where it has one: `x^2/(x cos(x) - sin(x))^2` is
+ // `(x sin(x) + cos(x))/(x cos(x) - sin(x))` there, continuous across the zeros of the
+ // base's derivative, where `-g/v` and the remainder each have a pole that cancels.
+ if (SolveByTrigonometricTowerAnsatz(expr, x) is { } fromTheRing)
+ return fromTheRing;
+ var (gTop, gBottom) = CancelledWithFunctionsAsIndeterminates(numerator, rest * derivative, x, expr);
+ // g' over v, cancelled: (A' B - A B')/(B^2 v) for g = A/B.
+ var above = (gTop.Differentiate(x) * gBottom - gTop * gBottom.Differentiate(x)).InnerSimplified;
+ var (rTop, rBottom) = CancelledWithFunctionsAsIndeterminates(above, MathS.Pow(gBottom, 2) * squared, x, expr);
+ if (rBottom.Nodes.Any(node => node == squared) || !rTop.ContainsNode(x) && !rBottom.ContainsNode(x) && TreeAnalyzer.IsZero(rTop))
+ return null;
+ var remainder = Functions.PartialFractions.Bare(rTop / rBottom);
+ if (Integration.ComputeIndefiniteIntegral(remainder, x) is not { } integral || integral.Nodes.Any(node => node is Integralf))
+ return null;
+ return -gTop / (gBottom * squared) + integral;
+ }
+
+ /// Whether is a trigonometric function, a logarithm or an exponential.
+ private static bool IsAFunctionOfTheVariable(Entity node)
+ => node is Sinf or Cosf or Tanf or Cotanf or Secantf or Cosecantf or Logf or Powf(Number, _);
+
/// Whether holds a fractional power of something in .
private static bool HasARadicalOf(Entity expr, Entity.Variable x)
=> expr.Nodes.Any(node => node is Powf(var @base, Number.Rational power) && power is not Number.Integer && @base.ContainsNode(x));
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
index 90cc04592..08211ea4b 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
@@ -784,6 +784,9 @@ private static Entity Normalized(Entity expr, Entity.Variable x) =>
// is `x^2/(L^2 sqrt(q))` cancelled, and was five terms over `L^5 (1 + L sqrt(q))`
// each searched for seconds when the reduction reached it first.
if ((answer = IndefiniteIntegralSolver.SolveByCancellingWithFunctionsAsIndeterminates(expr, x, integrateByParts)) is { }) return answer;
+ // A quotient by the square of a base with a function in it, by parts against the base's
+ // reciprocal where the base's derivative makes the rest exact.
+ if ((answer = IndefiniteIntegralSolver.SolveByPartsAgainstTheReciprocalOfASquaredBase(expr, x)) is { }) return answer;
// A polynomial over a power of a linear and something that is not a polynomial,
// the polynomial written in powers of the linear at its root: the part the power
// divides goes over the rest alone. Before the split, so that the whole polynomial
diff --git a/Sources/Tests/UnitTests/Calculus/SquaredBaseByPartsIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/SquaredBaseByPartsIntegralTest.cs
new file mode 100644
index 000000000..1187139a2
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/SquaredBaseByPartsIntegralTest.cs
@@ -0,0 +1,52 @@
+//
+// Copyright (c) 2019-2026 Angouri.
+// AngouriMath is licensed under MIT.
+// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
+// Website: https://am.angouri.org.
+//
+
+using System;
+using AngouriMath.Extensions;
+using Xunit;
+
+namespace AngouriMath.Tests.Calculus
+{
+ ///
+ /// A quotient by the square of a base with a function in it, by parts against the base's
+ /// reciprocal: N/(M v^2) is g v'/v^2 with g = N/(M v'), whose integral is
+ /// -g/v plus that of g'/v, which the base cancels from where its derivative is
+ /// one term. x^2/(a x cos(a x) - sin(a x))^2 was declined; Rubi's 4.7.7.
+ /// #718
+ ///
+ ///
+ /// Checked by differentiating back with a = 1.3 on both sides of zero.
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class SquaredBaseByPartsIntegralTest
+ {
+ [Theory]
+ [InlineData("x^2/(a*x*cos(a*x) - sin(a*x))^2")]
+ [InlineData("sin(a*x)^2/(a*x*cos(a*x) - sin(a*x))^2")]
+ [InlineData("sin(a*x)^3/(x*(a*x*cos(a*x) - sin(a*x))^2)")]
+ [InlineData("sin(a*x)^4/(x^2*(a*x*cos(a*x) - sin(a*x))^2)")]
+ [InlineData("x^2/(cos(a*x) + a*x*sin(a*x))^2")]
+ [InlineData("cos(a*x)^2/(cos(a*x) + a*x*sin(a*x))^2")]
+ [InlineData("cos(a*x)^3/(x*(cos(a*x) + a*x*sin(a*x))^2)")]
+ public void IsIntegratedAgainstTheReciprocalOfTheBase(string integrand)
+ {
+ var integral = integrand.ToEntity().Integrate("x");
+ Assert.DoesNotContain("integral(", integral.Stringize());
+ Entity Pinned(Entity e) => e.Substitute("a", 1.3);
+ var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
+ var original = Pinned(integrand.ToEntity());
+ foreach (var at in new[] { -2.3, -1.1, -0.4, 0.4, 1.1, 2.3 })
+ {
+ var want = original.Substitute("x", at).EvalNumerical();
+ var got = derivative.Substitute("x", at).EvalNumerical();
+ Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
+ < 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart)),
+ $"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
+ }
+ }
+ }
+}