diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 391832803..3d1e03d67 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -747,6 +747,21 @@ or of its square over the root. Rubi's 1.3.3 names those coefficients, and its r
| `"(c - 2*d*x)/((c + d*x)*sqrt(c^3 + 4*d^3*x^3))".ToEntity().Integrate("x")` | `integral(...)` | `2 c/d` times an arctangent of `sqrt(3 c^3) (1 + 2 d x/c)/sqrt(c^3 + 4 d^3 x^3)` over `sqrt(3 c^3)`, or an inverse hyperbolic tangent, by the sign of `c^3` |
| `"(1+x)/((x-2)*sqrt(1+x^3))".ToEntity().Integrate("x")` | `integral(...)` | `-(2/3) artanh((1 + x)^2/(3 sqrt(1 + x^3)))`, written as a logarithm |
+### `x` over a cubic binomial beside the root of another is integrated where that is elementary
+
+**Answers where there were none.** `x/((a + b x^3) sqrt(c + d x^3))` is elementary at `4 b c = a d`
+and at `8 b c + a d = 0`, Rubi's 1.1.3.4, as arctangents and inverse hyperbolic tangents of
+`sqrt(c + d x^3)` and of `(1 + q x)/sqrt(c + d x^3)` for `q = (d/c)^(1/3)`, and Welz's
+`x/((4 - x^3) sqrt(1 - x^3))` and the rest at those ratios were declined. They are answered in
+closed form now, by the sign of `c`
+([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"x/((4 - x^3)*sqrt(1 - x^3))".ToEntity().Integrate("x")` | `integral(...)` | two arctangents and two inverse hyperbolic tangents, of `sqrt(1 - x^3)` and of `(1 - 2^(1/3) x)/sqrt(1 - x^3)` and its kind |
+| `"x/((4*c + d*x^3)*sqrt(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | the same in `sqrt(c + d x^3)` and `q = (d/c)^(1/3)`, by the sign of `c` |
+| `"x/((8 - d*x^3)*sqrt(1 + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | `(artanh((1 + d^(1/3) x)^2/(3 sqrt(1 + d x^3))) - artanh(sqrt(1 + d x^3)/3))/(18 d^(2/3)) - atan(sqrt(3) (1 + d^(1/3) x)/sqrt(1 + d x^3))/(6 sqrt(3) d^(2/3))`, written with logarithms |
+
### `x^2` over a three-quarter power of a quadratic binomial beside another is integrated where that is elementary
**Answers where there were none.** `x^2/((A + B x^2)^(3/4) (C + D x^2))` at `B C - 2 A D = 0`, Rubi's
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 838463566..2e96723dc 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -4920,6 +4920,105 @@ Entity OverOnePlus(Entity k)
return holds ? answer : null;
}
+ ///
+ /// x/((a + b x^3) sqrt(c + d x^3)) at the two ratios where its integral is elementary,
+ /// Rubi's 1.1.3.4: 4 b c = a d and 8 b c + a d = 0, in closed form.
+ ///
+ ///
+ ///
+ /// With q = (d/c)^(1/3), the real root, and y = sqrt(c + d x^3), at
+ /// 4 b c = a d, for r = sqrt(c) where c is positive and
+ /// r = sqrt(-c) where it is negative:
+ ///
+ /// c > 0: q/(3 2^(2/3) b r) (artanh(y/r)/3 + atan(y/(sqrt(3) r))/sqrt(3)
+ /// - atan(sqrt(3) r (1 + 2^(1/3) q x)/y)/sqrt(3) - artanh(r (1 - 2^(1/3) q x)/y))
+ /// c < 0: -q/(3 2^(2/3) b r) (atan(y/r)/3 + artanh(y/(sqrt(3) r))/sqrt(3)
+ /// + artanh(sqrt(3) r (1 + 2^(1/3) q x)/y)/sqrt(3) + atan(r (1 - 2^(1/3) q x)/y))
+ ///
+ /// and at 8 b c + a d = 0, where the integrand is -(d/b) x/((8 c - d x^3) y), that
+ /// times
+ ///
+ /// c > 0: (artanh(r (1 + q x)^2/(3 y))/18 - artanh(y/(3 r))/18 - atan(sqrt(3) r (1 + q x)/y)/(6 sqrt(3)))/(r^3 q^2)
+ /// c < 0: -(atan(r (1 + q x)^2/(3 y))/18 + atan(y/(3 r))/18 - artanh(sqrt(3) r (1 + q x)/y)/(6 sqrt(3)))/(r^3 q^2)
+ ///
+ /// Rubi splits the second into three integrals, a substitution's in x^3, a linear
+ /// over a linear and a quadratic over a quadratic, each elementary, and their sum is the
+ /// form above; asked as three, two come back piecewise in the symbols and their sum holds
+ /// every combination of the arms. Every condition is decided as a value, and the answer is
+ /// differentiated back at sampled points before it is returned.
+ /// Welz's x/((4 - x^3) sqrt(1 - x^3)) and x/((8 - d x^3) sqrt(1 + d x^3)) were
+ /// declined, with the rest of 1.1.3.4 at those ratios.
+ /// https://github.com/asc-community/AngouriMath/issues/718
+ ///
+ ///
+ internal static Entity? SolveXOverACubicBinomialBesideTheRootOfAnother(Entity expr, Entity.Variable x, bool integrateByParts)
+ {
+ var (numerator, denominator) = Functions.SingleQuotient.Of(expr);
+ if (!TreeAnalyzer.TryGetPolynomial(numerator, x, out var above) || above.Count != 1
+ || !above.TryGetValue(EInteger.One, out var multiple) || multiple.ContainsNode(x))
+ return null;
+ Entity? radicand = null;
+ Entity below = Number.Integer.One;
+ foreach (var factor in Mulf.LinearChildren(denominator))
+ if (factor is Powf(var @base, Number.Rational half) && half.ERational.Equals(ERational.Create(1, 2)) && @base.ContainsNode(x))
+ {
+ if (radicand is not null)
+ return null;
+ radicand = @base;
+ }
+ else
+ below = below == Number.Integer.One ? factor : below * factor;
+ if (radicand is null || ACubicBinomial(radicand) is not var (c, d) || ACubicBinomial(below) is not var (a, b))
+ return null;
+ static bool Zero(Entity condition) => Functions.PartialFractions.IsZeroAsAValue(condition);
+ if (Zero(a) || Zero(b) || Zero(c) || Zero(d) || Zero(b * c - a * d))
+ return null;
+ var y = MathS.Sqrt(radicand);
+ var q = MathS.Pow(LowestOverTheSymbols(d / c), Number.Rational.Create(1, 3));
+ var cubeRootOfTwo = MathS.Pow(2, Number.Rational.Create(1, 3));
+ var sqrtOfThree = MathS.Sqrt(3);
+ Entity? answer = null;
+ if (Zero(4 * b * c - a * d))
+ {
+ var r = MathS.Sqrt(c);
+ var wherePositive = q / (3 * MathS.Sqr(cubeRootOfTwo) * b * r)
+ * (MathS.Hyperbolic.Artanh(y / r) / 3 + MathS.Arctan(y / (sqrtOfThree * r)) / sqrtOfThree
+ - MathS.Arctan(sqrtOfThree * r * (1 + cubeRootOfTwo * q * x) / y) / sqrtOfThree
+ - MathS.Hyperbolic.Artanh(r * (1 - cubeRootOfTwo * q * x) / y));
+ var s = MathS.Sqrt(LowestOverTheSymbols(-c));
+ var whereNegative = -q / (3 * MathS.Sqr(cubeRootOfTwo) * b * s)
+ * (MathS.Arctan(y / s) / 3 + MathS.Hyperbolic.Artanh(y / (sqrtOfThree * s)) / sqrtOfThree
+ + MathS.Hyperbolic.Artanh(sqrtOfThree * s * (1 + cubeRootOfTwo * q * x) / y) / sqrtOfThree
+ + MathS.Arctan(s * (1 - cubeRootOfTwo * q * x) / y));
+ answer = BySign(c, wherePositive, whereNegative);
+ }
+ else if (Zero(8 * b * c + a * d))
+ {
+ // The integrand is -(d/b) x/((8 c - d x^3) y).
+ var r = MathS.Sqrt(c);
+ var wherePositive = (MathS.Hyperbolic.Artanh(r * MathS.Sqr(1 + q * x) / (3 * y)) / 18 - MathS.Hyperbolic.Artanh(y / (3 * r)) / 18
+ - MathS.Arctan(sqrtOfThree * r * (1 + q * x) / y) / (6 * sqrtOfThree)) / (MathS.Pow(r, 3) * MathS.Sqr(q));
+ var s = MathS.Sqrt(LowestOverTheSymbols(-c));
+ var whereNegative = -(MathS.Arctan(s * MathS.Sqr(1 + q * x) / (3 * y)) / 18 + MathS.Arctan(y / (3 * s)) / 18
+ - MathS.Hyperbolic.Artanh(sqrtOfThree * s * (1 + q * x) / y) / (6 * sqrtOfThree)) / (MathS.Pow(s, 3) * MathS.Sqr(q));
+ answer = LowestOverTheSymbols(-d / b) * BySign(c, wherePositive, whereNegative);
+ }
+ if (answer is null)
+ return null;
+ answer = (multiple * answer).InnerSimplified;
+ bool holds;
+ using (MathS.Settings.DowncastingEnabled.Set(false))
+ holds = Functions.PartialFractions.HoldsAtSampledPoints(answer.Differentiate(x), expr, x);
+ return holds ? answer : null;
+
+ // `p + r x^3`, as `(p, r)`, each free of x.
+ (Entity, Entity)? ACubicBinomial(Entity binomial)
+ => TreeAnalyzer.TryGetPolynomial(binomial, x, out var read) && read.Count == 2
+ && read.TryGetValue(EInteger.Zero, out var constant) && read.TryGetValue(EInteger.FromInt32(3), out var cubic)
+ && !constant.ContainsNode(x) && !cubic.ContainsNode(x)
+ ? (constant, cubic) : null;
+ }
+
///
/// A root of a quadratic binomial beside another, 1/((A + B x^2)^(1/3) (C + D x^2))
/// with B C + 3 A D = 0 or B C - 9 A D = 0, and
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
index aa236edd4..8eefb0450 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
@@ -807,6 +807,9 @@ private static Entity Normalized(Entity expr, Entity.Variable x) =>
// `(1 + x + sqrt(3))/((1 + x - sqrt(3)) sqrt(1 + x^3))`. Before the reduction over the
// linear, which writes it as `1` and `2 sqrt(3)` over the linear, neither elementary.
if ((answer = IndefiniteIntegralSolver.SolveAPseudoEllipticQuotientOverTheRootOfACubicBinomial(expr, x)) is { }) return answer;
+ // x over a cubic binomial beside the root of another, at the two ratios where that is
+ // elementary: Welz's `x/((4 - x^3) sqrt(1 - x^3))`.
+ if ((answer = IndefiniteIntegralSolver.SolveXOverACubicBinomialBesideTheRootOfAnother(expr, x, integrateByParts)) is { }) return answer;
if ((answer = IndefiniteIntegralSolver.SolveByReducingThePolynomialOverALinearFactor(expr, x, integrateByParts)) is { }) return answer;
if (expr is Entity.Sumf or Entity.Minusf
&& (answer = IndefiniteIntegralSolver.SolveBySplittingSum(expr, x, integrateByParts)) is { })
diff --git a/Sources/Tests/UnitTests/Calculus/XOverACubicBinomialBesideTheRootOfAnotherIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/XOverACubicBinomialBesideTheRootOfAnotherIntegralTest.cs
new file mode 100644
index 000000000..9204487dd
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/XOverACubicBinomialBesideTheRootOfAnotherIntegralTest.cs
@@ -0,0 +1,62 @@
+//
+// 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
+{
+ ///
+ /// x/((a + b x^3) sqrt(c + d x^3)) at the two ratios where its integral is elementary,
+ /// Rubi's 1.1.3.4: 4 b c = a d, in closed form by the sign of c, and
+ /// 8 b c + a d = 0, as three integrals.
+ /// #718
+ ///
+ ///
+ /// Checked by differentiating back with c pinned to either sign and d = 0.7, on
+ /// both sides of 0 wherever the integrand is real.
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class XOverACubicBinomialBesideTheRootOfAnotherIntegralTest
+ {
+ private static readonly double[] Points = { -2.3, -1.4, -0.8, -0.3, 0.4, 0.9, 1.6, 2.4 };
+
+ [Theory]
+ // 4 b c = a d.
+ [InlineData("x/((4 - x^3)*sqrt(1 - x^3))", 1.3)]
+ [InlineData("x/((4 - d*x^3)*sqrt(-1 + d*x^3))", 1.3)]
+ [InlineData("x/((4*c + d*x^3)*sqrt(c + d*x^3))", 1.3)]
+ [InlineData("x/((4*c + d*x^3)*sqrt(c + d*x^3))", -1.3)]
+ // 8 b c + a d = 0.
+ [InlineData("x/((8 - d*x^3)*sqrt(1 + d*x^3))", 1.3)]
+ [InlineData("x/((8*c - d*x^3)*sqrt(c + d*x^3))", 1.3)]
+ [InlineData("x/((8*c - d*x^3)*sqrt(c + d*x^3))", -1.3)]
+ [InlineData("3*x/((8 + x^3)*sqrt(-1 + x^3))", 1.3)]
+ public void IsIntegrated(string integrand, double c)
+ {
+ var integral = integrand.ToEntity().Integrate("x");
+ Assert.DoesNotContain("integral(", integral.Stringize());
+ Entity Pinned(Entity e) => e.Substitute("c", c).Substitute("d", 0.7);
+ var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
+ var original = Pinned(integrand.ToEntity());
+ var compared = 0;
+ foreach (var at in Points)
+ {
+ var want = original.Substitute("x", at).EvalNumerical();
+ if (want.IsNaN || Math.Abs((double)want.ImaginaryPart) > 1e-12 * Math.Max(1, Math.Abs((double)want.RealPart)))
+ continue;
+ var got = derivative.Substitute("x", at).EvalNumerical();
+ compared++;
+ 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}");
+ }
+ Assert.True(compared >= 2, $"only {compared} points were real for {integrand}");
+ }
+ }
+}