diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 80e69aa15..4cf77a562 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -1058,6 +1058,21 @@ secant too now, and the integrand is `sgn(cos(x)) (1 + u^2)^(3/2)/(a + b u)^2` i
| `"sec(x)^7/(a + b*tan(x))^3".ToEntity().Integrate("x")` | `integral(...)` | 1,253 characters |
| `"sec(x)/(a + b*cot(x))".ToEntity().Integrate("x")` | `integral(...)` | 571 characters |
+### A quadratic with rational roots takes Euler's third substitution at one of them
+
+**Answers where there were none.** `1/(x + sqrt(3 - 2x - x^2))` was declined. Its leading coefficient is negative and
+its constant term not a square, so the second substitution wrote `sqrt(3)` into every coefficient and the rational
+integrator could not finish. `3 - 2x - x^2` is `(1 - x)(3 + x)`: shifted to a root, the constant term is zero, and the
+third substitution answers with rational coefficients throughout. A quadratic with a positive leading coefficient
+keeps the first substitution, which was already answering it
+([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"1/(x + sqrt(3 - 2*x - x^2))".ToEntity().Integrate("x")` | `integral(...)` | 389 characters |
+| `"1/(x + sqrt(3 - 2*x - x^2))^3".ToEntity().Integrate("x")` | `integral(...)` | 1,160 characters |
+| `"1/(2*x + sqrt(3 - 2*x - x^2))".ToEntity().Integrate("x")` | `integral(...)` | 253 characters |
+
### A root of a multiple of the radicand beside Euler's sum is the same root
**Answers where there were none.** `sqrt(g Q) (d + e x + f sqrt(Q))^n` was declined, with the root of `g Q` below the
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 557c5f1ba..12ba5197e 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -18870,6 +18870,21 @@ private static bool VanishesIdentically(Entity expr)
return Functions.PartialFractions.Bare(inner.Simplify()).Evaled is Number.Complex { IsZero: true };
}
+ ///
+ /// A rational root of a x^2 + b x + c with rational coefficients, the larger, or
+ /// null where its roots are not rational.
+ ///
+ private static Entity? RationalRootOf(Entity a, Entity b, Entity c)
+ {
+ if (a.Evaled is not Number.Rational ra || b.Evaled is not Number.Rational rb || c.Evaled is not Number.Rational rc
+ || ra.Evaled is Number.Complex { IsZero: true })
+ return null;
+ var discriminant = (rb * rb - 4 * ra * rc).InnerSimplified;
+ if (discriminant.Evaled is not Number.Rational { IsNegative: false } || MathS.Sqrt(discriminant).InnerSimplified.Evaled is not Number.Rational root)
+ return null;
+ return ((-rb + root) / (2 * ra)).InnerSimplified;
+ }
+
///
/// as a x^2 + b x + c, read through a constant below the
/// bar as well: Rubi writes (a f^2 + e x (2 d + e x))/f^2 for
@@ -19079,6 +19094,21 @@ node is Powf(var @base, Number.Rational r) && byRadicand.TryGetValue(@base, out
else if (aRational) which = 1;
else if (cRational) which = 2;
else if (aPositive) which = 1;
+ else if (RationalRootOf(a, b, c) is { } rationalRoot)
+ {
+ // Neither root rational and a < 0, the quadratic's own roots are: `3 - 2x - x^2`
+ // is `(1 - x)(3 + x)`, and the second substitution wrote `sqrt(3)` into every
+ // coefficient, after which `1/(x + sqrt(3 - 2x - x^2))` was declined. Shifted to a
+ // root, x = y + r, the constant term is zero and the third substitution's, with
+ // rational coefficients throughout. Where a > 0 the first substitution answers
+ // first and faster: `sqrt(12x^2 + 17x + 6)/((2 + 3x)^2 (30 + 31x - 12x^2)^2)`
+ // took 1.4 s by it and timed out by the shift.
+ var y = Variable.CreateUnique(expr, "y_euler");
+ if (SolveByEulerSubstitution(expr.Substitute(x, y + rationalRoot), y) is not { } inY)
+ return null;
+ var writtenBack = radicand.Substitute(x, y + rationalRoot).Substitute(y, x - rationalRoot);
+ return inY.Substitute(y, x - rationalRoot).Replace(node => node == writtenBack ? radicand : node).InnerSimplified;
+ }
else if (cPositive) which = 2;
else if (aValue is null) which = 1;
else if (cValue is null) which = 2;
diff --git a/Sources/Tests/UnitTests/Calculus/EulerSubstitutionTest.cs b/Sources/Tests/UnitTests/Calculus/EulerSubstitutionTest.cs
index e281a6210..34efa8cc3 100644
--- a/Sources/Tests/UnitTests/Calculus/EulerSubstitutionTest.cs
+++ b/Sources/Tests/UnitTests/Calculus/EulerSubstitutionTest.cs
@@ -119,6 +119,18 @@ private static void DifferentiatesBack(string integrand, double[] points, params
[InlineData("sqrt(x^2 + 2*x)/x", new[] { 0.3, 0.9, 1.7, 2.6 })]
public void TheRootAtZero(string integrand, double[] points) => DifferentiatesBack(integrand, points, ("r", 1.7));
+ ///
+ /// Neither sqrt(a) nor sqrt(c) rational, but the quadratic's roots: shifted
+ /// to one, the root is at zero and the third substitution has rational coefficients,
+ /// where the second wrote sqrt(3) into every one and was declined. Rubi's 1.3.2.
+ ///
+ [Theory]
+ [InlineData("1/(x + sqrt(3 - 2*x - x^2))", new[] { -2.5, -1.2, 0.3, 0.8 })]
+ [InlineData("1/(x + sqrt(3 - 2*x - x^2))^3", new[] { -2.5, -1.2, 0.3, 0.8 })]
+ [InlineData("x/(x + sqrt(3 - 2*x - x^2))", new[] { -2.5, -1.2, 0.3, 0.8 })]
+ [InlineData("1/(2*x + sqrt(3 - 2*x - x^2))", new[] { -2.5, -1.2, 0.3, 0.8 })]
+ public void ARationalRootOfTheQuadratic(string integrand, double[] points) => DifferentiatesBack(integrand, points);
+
///
/// Reached one level down, which is why the rule is not scoped: a nested radical under
/// u = sqrt(1 + x), and the remainders of by parts against an inverse function.