diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index b962bfd10..f95f8dd4b 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -528,6 +528,22 @@ the linear at its root now, and each piece is the table's
| `"t^9/(a + b*t)^8".ToEntity().Integrate("t")` | `integral(...)` | powers of `a/b + t` and a logarithm, in 0.03 s |
| `"x^4/(a + b*sqrt(x))^8".ToEntity().Integrate("x")` | `integral(...)` | the same in `sqrt(x)`, in 0.5 s; a minute on the unreleased master |
+### Two roots of linears over a linear off the real line are integrated
+
+**Answers where there were none.** `1/(sqrt(x) sqrt(a + b x) (1 - i x))` was declined. The closed forms
+for two roots of linears over a third, an arctangent and a logarithm, were chosen by the sign of a
+quantity that, over a linear whose coefficients are not real, has none -- `-i a - b < 0` is NaN, the
+complex numbers not being ordered -- and on the unreleased master the answer was a piecewise on that
+sign which held at no point. Both forms use nothing about their root but `sqrt(q)^2 = q`, so either
+is an antiderivative wherever the quantity is not zero, whatever its phase, and with the imaginary
+unit in the quantity the one for a positive quantity is taken alone
+([#718](https://github.com/asc-community/AngouriMath/issues/718)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"1/(sqrt(x)*sqrt(a + b*x)*(1 - i*x))".ToEntity().Integrate("x")` | `integral(...)` | `2 arctan(sqrt(-i a - b) sqrt(x)/sqrt(a + b x))/sqrt(-i a - b)` |
+| `"sqrt(x)*sqrt(a + b*x)/(1 + i*x)".ToEntity().Integrate("x")` | `integral(...)` | a root, a logarithm and an arctangent, piecewise in the sign of `b` |
+
### A polynomial over a power of a quadratic with a sum of symbols in it is reduced
**Answers where there were none.** The reduction of `N(x)/Q(x)^n` divides `N` by the quadratic a
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 10e0310fe..a24a2f342 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -10698,7 +10698,7 @@ is not var (algebraic, ofTheLogarithm, ofTheThirdKind))
var r = LowestOverTheSymbols(d / b);
answer = answer + BySign(r,
ofTheLogarithm * MathS.Ln((1 + MathS.Sqrt(r) * root) / (1 - MathS.Sqrt(r) * root)) / MathS.Sqrt(r),
- 2 * ofTheLogarithm * MathS.Arctan(MathS.Sqrt(-r) * root) / MathS.Sqrt(-r));
+ 2 * ofTheLogarithm * MathS.Arctan(MathS.Sqrt(-r) * root) / MathS.Sqrt(-r), alsoOffTheRealLine: true);
}
if (ofTheThirdKind != Number.Integer.Zero)
{
@@ -10708,7 +10708,7 @@ is not var (algebraic, ofTheLogarithm, ofTheThirdKind))
var rho = LowestOverTheSymbols(-atThePole[1] / atThePole[0]);
answer = answer + BySign(rho,
-2 * ofTheThirdKind * MathS.Arctan(MathS.Sqrt(rho) * root) / MathS.Sqrt(rho),
- -ofTheThirdKind * MathS.Ln((1 + MathS.Sqrt(-rho) * root) / (1 - MathS.Sqrt(-rho) * root)) / MathS.Sqrt(-rho));
+ -ofTheThirdKind * MathS.Ln((1 + MathS.Sqrt(-rho) * root) / (1 - MathS.Sqrt(-rho) * root)) / MathS.Sqrt(-rho), alsoOffTheRealLine: true);
}
return (constantBelow == Number.Integer.One ? answer : answer / constantBelow).InnerSimplified;
}
@@ -11316,10 +11316,21 @@ private sealed record ALinearBesideTheRoot(Entity Linear, Entity G, Entity H, in
// where it holds, for a quantity with symbols in it, as `1/(a - x^2)` is answered. A
// number times even powers of symbols has the number's sign wherever the symbols are
// real and not zero, which is the generic case: `-b^2` in `a^2 - b^2 x^2` is negative.
- private static Entity BySign(Entity quantity, Entity wherePositive, Entity whereNegative)
- => SignOfANumberTimesEvenPowers(quantity) is { } sign
- ? (sign < 0 ? whereNegative : wherePositive)
- : MathS.Piecewise((wherePositive, new Greaterf(quantity, Number.Integer.Zero)), (whereNegative, new Lessf(quantity, Number.Integer.Zero)));
+ // Off the real line neither sign holds, the complex numbers not being ordered, and the
+ // piecewise had no arm there: `1/(sqrt(x) sqrt(a + b x) (1 - i x))` was answered with
+ // nothing at any point. Where the caller's form for a positive quantity uses nothing about
+ // its root but `sqrt(z)^2 = z`, as an arctangent or a logarithm does and an arcsine does
+ // not, it is an antiderivative wherever the quantity is not zero, whatever its phase -- the
+ // sign only chooses the form that is real on the real line -- and the caller says so with
+ // alsoOffTheRealLine: a quantity with the imaginary unit in it then takes that form alone.
+ private static Entity BySign(Entity quantity, Entity wherePositive, Entity whereNegative, bool alsoOffTheRealLine = false)
+ {
+ if (SignOfANumberTimesEvenPowers(quantity) is { } sign)
+ return sign < 0 ? whereNegative : wherePositive;
+ if (alsoOffTheRealLine && HoldsTheImaginaryUnit(quantity.InnerSimplified))
+ return wherePositive;
+ return MathS.Piecewise((wherePositive, new Greaterf(quantity, Number.Integer.Zero)), (whereNegative, new Lessf(quantity, Number.Integer.Zero)));
+ }
// The same where the form for a positive first quantity is chosen by the sign of a second,
// as one piecewise rather than one inside another.
diff --git a/Sources/Tests/UnitTests/Calculus/RootsOfLinearsOffTheRealLineIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/RootsOfLinearsOffTheRealLineIntegralTest.cs
new file mode 100644
index 000000000..5efad5f17
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/RootsOfLinearsOffTheRealLineIntegralTest.cs
@@ -0,0 +1,49 @@
+//
+// 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
+{
+ ///
+ /// The roots of two linears over a linear whose coefficients are not real, where the closed
+ /// forms chose between an arctangent and a logarithm by the sign of a quantity that has none,
+ /// and the answer held at no point.
+ /// #718
+ ///
+ ///
+ /// Compared as complex numbers, the integrands being complex, and differentiated before the
+ /// symbols are pinned: a piecewise arm whose condition compares a number off the real line, pinned
+ /// first and then differentiated, made the whole derivative NaN.
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class RootsOfLinearsOffTheRealLineIntegralTest
+ {
+ [Theory]
+ [InlineData("1/(sqrt(x)*sqrt(a + b*x)*(1 - i*x))")]
+ [InlineData("sqrt(x)/(sqrt(a + b*x)*(1 + i*x))")]
+ [InlineData("sqrt(x)*sqrt(a + b*x)/(1 + i*x)")]
+ public void IsIntegratedOverTheLinear(string integrand)
+ {
+ var integral = integrand.ToEntity().Integrate("x");
+ Assert.DoesNotContain("integral(", integral.Stringize());
+ Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.6);
+ var derivative = Pinned(integral.Substitute("C", 0).Differentiate("x"));
+ var original = Pinned(integrand.ToEntity());
+ foreach (var at in new[] { 0.3, 0.7, 1.2, 2.0 })
+ {
+ 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) + Math.Abs((double)want.ImaginaryPart)),
+ $"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
+ }
+ }
+ }
+}