diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 78a771133..ff524e1a1 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -583,6 +583,18 @@ unevaluated, is answered by this route as well.
| `"(a*x+2*b*n*ln(c*x^n))/(a*x^2+b*x*ln(c*x^n)^2)".ToEntity().Integrate("x")` | `integral(...)` | 37 characters |
| `"tanh(a+2*ln(x))^2/x^3".ToEntity().Integrate("x")` | `integral(...)` | 7,796 characters |
+### A symbolic cubic with a repeated root is written over its roots
+
+**Answers where there were none.** `1/(x^3 - 3b x + 2b^(3/2))` was left unevaluated: its coefficients are symbolic, so
+no numeric root finder applies, and its discriminant vanishes identically. Such a cubic is `a (x - r)^2 (x - t)` with
+`r` and `t` rational in its coefficients, and is written so before the partial fractions
+([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"1/(x^3-3*b*x+2*b^(3/2))".ToEntity().Integrate("x")` | `integral(...)` | 122 characters |
+| `"1/(-9*b*x+9*x^3+2*b^(3/2)*sqrt(3))".ToEntity().Integrate("x")` | `integral(...)` | 176 characters |
+
### A symbol shared by a numerator sum's coefficients is taken out before the partial fractions
**Answers where there were none.** `(b d + 2c d x)^9/(a + b x + c x^2)^3` ran past a minute, where
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index d1fbe9ec7..d4937df7e 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -29334,6 +29334,79 @@ static bool IsZero(Entity value) => value.InnerSimplified.Evaled is Number.Compl
return written == expr ? null : Integration.ComputeAsTheSameQuestion(written, x, integrateByParts);
}
+ ///
+ /// A quotient with a cubic in below the bar whose coefficients are
+ /// symbolic and whose discriminant vanishes identically, with the cubic written over its
+ /// roots: a x^3 + b x^2 + c x + d is a (x - r)^2 (x - s) with the double root
+ /// r = (9ad - bc)/(2(b^2 - 3ac)) and the simple one
+ /// s = (4abc - 9a^2 d - b^3)/(a(b^2 - 3ac)), or a (x + b/(3a))^3 where
+ /// b^2 - 3ac vanishes too.
+ ///
+ ///
+ /// Rubi's 1.3.1 1/(9x^3 - 9bx + 2 sqrt(3) b^(3/2)) was left unevaluated, and the same
+ /// written 9 (x - sqrt(b/3))^2 (x + 2 sqrt(b/3)) is answered in 60 ms. The factored
+ /// form is checked against the cubic before it is handed on.
+ /// https://github.com/asc-community/AngouriMath/issues/718
+ ///
+ internal static Entity? SolveACubicWithARepeatedRootOverItsRoots(Entity expr, Entity.Variable x, bool integrateByParts)
+ {
+ if (!Integration.AnsweringTheQuestionAsked)
+ return null;
+ var (above, below) = Functions.SingleQuotient.Of(Functions.SingleQuotient.Combine(expr));
+ if (!below.ContainsNode(x))
+ return null;
+ Entity rest = Number.Integer.One;
+ Entity? written = null;
+ foreach (var factor in Mulf.LinearChildren(below))
+ {
+ if (written is null && factor is Sumf or Minusf && TreeAnalyzer.TryGetPolynomial(factor, x, out var monomials)
+ && monomials.Keys.All(k => k.Sign >= 0 && k.CompareTo(EInteger.FromInt32(3)) <= 0)
+ && monomials.TryGetValue(EInteger.FromInt32(3), out var a) && !VanishesIdentically(a)
+ && monomials.Values.All(coefficient => !coefficient.ContainsNode(x))
+ && monomials.Values.Any(coefficient => coefficient.InnerSimplified.Evaled is not Number.Complex))
+ {
+ Entity Coefficient(int k) => monomials.TryGetValue(EInteger.FromInt32(k), out var value) ? value : Number.Integer.Zero;
+ var (b, c, d) = (Coefficient(2), Coefficient(1), Coefficient(0));
+ var discriminant = 18 * a * b * c * d - 4 * MathS.Pow(b, 3) * d + MathS.Sqr(b) * MathS.Sqr(c) - 4 * a * MathS.Pow(c, 3) - 27 * MathS.Sqr(a) * MathS.Sqr(d);
+ if (!VanishesIdentically(discriminant))
+ return null;
+ var depressed = (MathS.Sqr(b) - 3 * a * c).InnerSimplified;
+ Entity? over = null;
+ // The roots simplified first, which folds the quotients of the coefficients to
+ // short ones -- `sqrt(b)` rather than a product of six numbers and it -- where
+ // the simplified form still expands back to the cubic, and as they are where not.
+ foreach (var simplify in new[] { true, false })
+ {
+ // Without the condition the simplification adds for b^2 - 3ac, which this
+ // case already assumes: the generic case is the one answered.
+ Entity Tidy(Entity e) => simplify ? e.Simplify() is Providedf(var value, _) ? value : e.Simplify() : e.InnerSimplified;
+ Entity candidate;
+ if (VanishesIdentically(depressed))
+ candidate = a * MathS.Pow(x + Tidy(b / (3 * a)), 3);
+ else
+ {
+ var r = Tidy((9 * a * d - b * c) / (2 * depressed));
+ var t = Tidy((4 * a * b * c - 9 * MathS.Sqr(a) * d - MathS.Pow(b, 3)) / (a * depressed));
+ candidate = a * MathS.Sqr(x - r) * (x - t);
+ }
+ if (VanishesIdentically((candidate - factor).Expand()))
+ {
+ over = candidate;
+ break;
+ }
+ }
+ if (over is null)
+ return null;
+ written = over;
+ continue;
+ }
+ rest *= factor;
+ }
+ if (written is null)
+ return null;
+ return Integration.ComputeAsTheSameQuestion(above / (rest * written), x, integrateByParts);
+ }
+
///
/// A quotient whose denominator is a sum every term of which carries the same power of one
/// linear form in , with that power taken out below the bar:
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
index 69f3bbe02..cbfa55111 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
@@ -1223,6 +1223,11 @@ private static Entity WithItsPiecewiseSumsCombined(Entity expr)
if (expr is Entity.Sumf or Entity.Minusf
&& (answer = IndefiniteIntegralSolver.SolveByGatheringACommonPolynomialFactorOfASum(expr, x, integrateByParts)) is { })
return answer;
+ // A cubic below the bar with symbolic coefficients and a repeated root, written over
+ // its roots: `1/(x^3 - 3b x + 2b^(3/2))` is `1/((x - sqrt(b))^2 (x + 2 sqrt(b)))`.
+ if (expr is Entity.Divf or Entity.Powf
+ && (answer = IndefiniteIntegralSolver.SolveACubicWithARepeatedRootOverItsRoots(expr, x, integrateByParts)) is { })
+ return answer;
// The same factor taken out of a sum below the bar: `1/(a x + b x/ln(c x^n))` is
// `1/(x (a + b/ln(c x^n)))`, a function of the logarithm beside its differential.
if (expr is Entity.Divf or Entity.Powf
diff --git a/Sources/Tests/UnitTests/Calculus/ACubicWithARepeatedRootIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/ACubicWithARepeatedRootIntegralTest.cs
new file mode 100644
index 000000000..458efcf48
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/ACubicWithARepeatedRootIntegralTest.cs
@@ -0,0 +1,57 @@
+//
+// 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 cubic with symbolic coefficients and a repeated root below the bar, written over its
+ /// roots: Rubi's 1.3.1 1/(9x^3 - 9bx + 2 sqrt(3) b^(3/2)), which was left unevaluated.
+ /// #718
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class ACubicWithARepeatedRootIntegralTest
+ {
+ private static void DifferentiatesBack(string integrand, params (string, double)[] pins)
+ {
+ var integral = integrand.ToEntity().Integrate("x");
+ Assert.DoesNotContain("integral(", integral.Stringize());
+
+ var pinned = integral.Substitute("C", 0);
+ Entity original = integrand.ToEntity();
+ foreach (var (name, value) in pins)
+ {
+ pinned = pinned.Substitute(name, value);
+ original = original.Substitute(name, value);
+ }
+ var derivative = pinned.Differentiate("x");
+ // Away from the roots, at b > 0, where the coefficients are real.
+ foreach (var at in new[] { -3.1, -0.4, 0.3, 2.7 })
+ {
+ var got = derivative.Substitute("x", at).EvalNumerical();
+ var want = original.Substitute("x", at).EvalNumerical();
+ var difference = Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart);
+ var scale = Math.Max(1.0, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
+ Assert.True(difference / scale < 1e-8,
+ $"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
+ }
+ }
+
+ [Theory]
+ [InlineData("1/(-9*b*x+9*x^3+2*b^(3/2)*sqrt(3))")]
+ [InlineData("x/(x^3-3*b*x+2*b^(3/2))")]
+ [InlineData("1/(x^3+3*k*x^2+3*k^2*x+k^3)")]
+ public void IsAnsweredAndDifferentiatesBack(string integrand)
+ {
+ DifferentiatesBack(integrand, ("b", 1.3), ("k", 0.7));
+ DifferentiatesBack(integrand, ("b", 2.2), ("k", -1.6));
+ }
+ }
+}