diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index f0b64c24b..cc36da245 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -396,6 +396,19 @@ in Rubi's 1.1.3.4 come out shorter as well, and those that took two seconds take
| `"1/(x^8*(a + b*x^3)*(c + d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,217 characters |
| `"1/(x^6*(a + b*x^4)*(c + d*x^4))".ToEntity().Integrate("x")` | `integral(...)` | 795 characters |
+### A linear and a quadratic to one power are integrated as one binomial
+
+**Answers where there were none.** `1/((1 + x)^(1/3) (1 - x + x^2)^(1/3))` was declined. A linear and a quadratic to
+one power that is not whole, whose product is `A + B x^3`, are now integrated as `(L^p Q^p/(A + B x^3)^p)` times the
+integral over `(A + B x^3)^p`. The quotient is constant on each interval between the roots, so it stays in the answer
+as written ([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"1/((1+x)^(1/3)*(1-x+x^2)^(1/3))".ToEntity().Integrate("x")` | `integral(...)` | 263 characters |
+| `"1/((1-x)^(1/3)*(1+x+x^2)^(1/3))".ToEntity().Integrate("x")` | `integral(...)` | 269 characters |
+| `"1/((b*k-c*k*x)^(1/3)*(b^2+b*c*x+c^2*x^2)^(1/3))".ToEntity().Integrate("x")` | `integral(...)` | 881 characters |
+
### A sine or a cosine over a symbolic quadratic or binomial is split over its roots with the coefficients named
**Answers where there were none.** A quadratic or a binomial with a compound coefficient below a sine or a cosine is
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 30b24cbbb..5a0a8ccab 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -19919,6 +19919,75 @@ Piecewise piecewise when piecewise.Cases.Any() => piecewise.Cases.First().Expres
return Functions.PartialFractions.DerivativeHoldsAtSampledPoints(answer, expr, x) ? answer : null;
}
+ ///
+ /// A linear and a quadratic to one power that is not whole, as one binomial:
+ /// integral g L^p Q^p = (L^p Q^p/P^p) integral g P^p where P = L Q is
+ /// A + B x^3, as (1 + x) (1 - x + x^2) is 1 + x^3.
+ ///
+ ///
+ /// L^p Q^p/P^p is constant wherever it is continuous, for the reason
+ /// gives, and the rules for a power
+ /// of a binomial answer the rest. Rubi's 1.2.1.2 1/((1 + x)^(1/3) (1 - x + x^2)^(1/3))
+ /// and 1/((b e - c e x)^(1/3) (b^2 + b c x + c^2 x^2)^(1/3)) were declined.
+ /// https://github.com/asc-community/AngouriMath/issues/718
+ ///
+ internal static Entity? SolveALinearAndAQuadraticToOnePowerAsOneBinomial(Entity expr, Entity.Variable x, bool integrateByParts)
+ {
+ if (!Integration.AnsweringTheQuestionAsked)
+ return null;
+ // Without a leading `1 *`, which is another spelling to the rules that read the result.
+ static Entity Times(Entity a, Entity b) => a == Number.Integer.One ? b : a * b;
+ static Entity Over(Entity a, Entity b) => a / b;
+ int? Degree(Entity polynomial)
+ {
+ if (!TreeAnalyzer.TryGetPolynomial(polynomial, x, out var read) || read.Keys.Any(key => key.Sign < 0))
+ return null;
+ var present = read.Where(term => !VanishesIdentically(term.Value.Expand())).Select(term => term.Key).ToList();
+ return present.Count == 0 || present.Max() is not { } top || !top.CanFitInInt32() ? null : top.ToInt32Unchecked();
+ }
+ var (numerator, denominator) = Functions.SingleQuotient.Of(expr);
+ var factors = new List<(Entity Base, Number.Rational Power, bool Below, Entity Factor, int Degree)>();
+ Entity rest = Number.Integer.One;
+ foreach (var (side, below) in new[] { (numerator, false), (denominator, true) })
+ foreach (var factor in Mulf.LinearChildren(side))
+ {
+ if (factor is Powf(var @base, Number.Rational power) && power is not Number.Integer
+ && Degree(@base) is (1 or 2) and var degree)
+ factors.Add((@base, power, below, factor, degree));
+ else
+ rest = below ? Over(rest, factor) : Times(rest, factor);
+ }
+ Number.Rational Signed((Entity Base, Number.Rational Power, bool Below, Entity Factor, int Degree) f) => f.Below ? (Number.Rational)(-f.Power) : f.Power;
+ for (var i = 0; i < factors.Count; i++)
+ for (var j = 0; j < factors.Count; j++)
+ {
+ var (first, second) = (factors[i], factors[j]);
+ var power = Signed(first);
+ if (first.Degree != 1 || second.Degree != 2 || power != Signed(second)
+ || !TreeAnalyzer.TryGetPolynomial(first.Base * second.Base, x, out var product))
+ continue;
+ var terms = product.Where(term => !VanishesIdentically(term.Value.Expand())).ToDictionary(term => term.Key, term => term.Value);
+ if (terms.Count != 2 || !terms.ContainsKey(EInteger.Zero) || !terms.ContainsKey(EInteger.FromInt32(3)))
+ continue;
+ var binomial = terms[EInteger.Zero].Expand().InnerSimplified
+ + terms[EInteger.FromInt32(3)].Expand().InnerSimplified * MathS.Pow(x, Number.Integer.Create(3));
+ Entity others = rest;
+ for (var k = 0; k < factors.Count; k++)
+ if (k != i && k != j)
+ others = factors[k].Below ? Over(others, factors[k].Factor) : Times(others, factors[k].Factor);
+ // Spelled as a quotient where the power is negative, as the rules for a power of a
+ // binomial read it.
+ var asked = power.IsNegative ? Over(others, MathS.Pow(binomial, (Number.Rational)(-power))) : Times(others, MathS.Pow(binomial, power));
+ if (Integration.ComputeAsAQuestionOfItsOwn(asked, x, integrateByParts) is not { } joined)
+ return null;
+ if (!Functions.PartialFractions.DerivativeHoldsAtSampledPoints(joined, asked, x))
+ return null;
+ var constant = MathS.Pow(first.Base, power) * MathS.Pow(second.Base, power) / MathS.Pow(binomial, power);
+ return constant * joined;
+ }
+ return null;
+ }
+
///
/// A power of a linear that is not whole, times a linear, over a whole power of a quadratic,
/// with the power of the quadratic lowered one at a time:
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
index 055b4fba4..606c7cfd4 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
@@ -669,6 +669,9 @@ private static Entity WithItsPiecewiseSumsCombined(Entity expr)
// linear is written once: `(2 + 3x)^4/((1 - 2x)^(5/2) (3 + 5x)^(5/2))` took forty-five
// seconds there, and over `(3 - x - 10x^2)^(5/2)` it takes half of one.
if ((answer = IndefiniteIntegralSolver.SolveTwoLinearsToOnePowerAsOneQuadratic(expr, x, integrateByParts)) is { }) return answer;
+ // A linear and a quadratic to one power as one binomial, `(1 + x) (1 - x + x^2)` as
+ // `1 + x^3`, which the rules for a power of a binomial answer.
+ if ((answer = IndefiniteIntegralSolver.SolveALinearAndAQuadraticToOnePowerAsOneBinomial(expr, x, integrateByParts)) is { }) return answer;
if ((answer = IndefiniteIntegralSolver.SolveByWritingEachLinearOnce(expr, x, integrateByParts)) is { }) return answer;
// A rational function with numbers for coefficients over a denominator past the twelfth
// degree, by Hermite's reduction before anything searches: nothing below answered one.
diff --git a/Sources/Tests/UnitTests/Calculus/ALinearAndAQuadraticToOnePowerIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/ALinearAndAQuadraticToOnePowerIntegralTest.cs
new file mode 100644
index 000000000..20597337e
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/ALinearAndAQuadraticToOnePowerIntegralTest.cs
@@ -0,0 +1,61 @@
+//
+// 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 linear and a quadratic to one power whose product is a binomial in x^3,
+ /// integrated over the binomial: (1 + x) (1 - x + x^2) is 1 + x^3. Rubi's
+ /// 1.2.1.2 rows, sampled on both sides of the linear's root, where the cube roots are complex.
+ /// #718
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class ALinearAndAQuadraticToOnePowerIntegralTest
+ {
+ 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");
+ foreach (var at in new[] { -2.3, -0.7, 0.4, 1.9 })
+ {
+ 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/((1+x)^(1/3)*(1-x+x^2)^(1/3))")]
+ [InlineData("1/((1-x)^(1/3)*(1+x+x^2)^(1/3))")]
+ public void WithNumbersIsAnsweredAndDifferentiatesBack(string integrand)
+ => DifferentiatesBack(integrand);
+
+ [Fact]
+ public void WithSymbolsIsAnsweredAndDifferentiatesBack()
+ {
+ const string integrand = "1/((b*k-c*k*x)^(1/3)*(b^2+b*c*x+c^2*x^2)^(1/3))";
+ DifferentiatesBack(integrand, ("b", 2), ("c", 3), ("k", 0.7));
+ DifferentiatesBack(integrand, ("b", -2), ("c", 3), ("k", -1.5));
+ }
+ }
+}