diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index a14f230c9..38c1dc016 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -129,6 +129,19 @@ since semantic versioning admits it.
Measured on the suite: **7 of 8,525 tests** referenced the old reading — five boolean-solver inputs
written `A | B`, and two that existed to record this spelling as at risk.
+### A power of x times `atanh(sqrt(e) x/sqrt(d + e x^2))` is integrated by parts against the root
+
+**Answers where there were none.** `x atanh(sqrt(e) x/sqrt(d + e x^2))` was declined, and so were twelve more of Rubi's
+7.3.7, every power of `x` from `x^6` to `1/x^9` but `1/x`. The logarithm `atanh` is written as has the derivative
+`sqrt(e)/sqrt(d + e x^2)`, and by parts what is left is `x^(m + 1)/sqrt(d + e x^2)`; differentiated as written it was a
+quotient of two sums with a root in each, which the search never brought down to the root
+([#233](https://github.com/asc-community/AngouriMath/issues/233)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"atanh(x*sqrt(k)/sqrt(d+k*x^2))".ToEntity().Integrate("x")` | `integral(...)` | `x atanh(...) - sqrt(d + k x^2)/sqrt(k)`, written in the logarithm |
+| `"atanh(x*sqrt(k)/sqrt(d+k*x^2))/x^5".ToEntity().Integrate("x")` | `integral(...)` | by parts onto `1/(x^4 sqrt(d + k x^2))` |
+
### A power of x is taken out of a bracket to find the derivative of a product of powers
**Answers where there were none.** `x^(2n) (c + d x)^n (2 c x + 3 d x^2)`, Rubi's 1.3.1, was declined. A bracket that
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 148c4e3f3..127392b67 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -639,6 +639,76 @@ private static bool IsADerivativeOfAFactorBelowTheBar(Entity expr, Entity.Variab
return Integration.ComputeAsTheSameQuestion(written, x, integrateByParts);
}
+ ///
+ /// A power of x times artanh(A x/sqrt(d + B x^2)) with A^2 = B, by parts:
+ /// the logarithm ln((1 + u)/(1 - u)) that artanh(u) is written as has the
+ /// derivative 2 u'/(1 - u^2), and for this u, 1 - u^2 = d/(d + B x^2) and
+ /// u' = A d/(d + B x^2)^(3/2), so it is 2 A/sqrt(d + B x^2). So
+ /// integral x^m ln(...) = x^(m + 1)/(m + 1) ln(...) - 2 A/(m + 1) integral x^(m + 1)/sqrt(d + B x^2),
+ /// for every whole m but -1. Rubi's 7.3.7, x^m artanh(sqrt(e) x/sqrt(d + e x^2)).
+ /// https://github.com/asc-community/AngouriMath/issues/233
+ ///
+ ///
+ /// The search takes it by parts too, and differentiates the logarithm as written: a quotient
+ /// of two sums with a root in each, which it never brought down to the root alone, and the
+ /// remainder it asked about ran past the budget. The identity is algebraic, with no branch in
+ /// it: it holds wherever d is not 0 and the root is.
+ ///
+ internal static Entity? SolveByPartsAgainstAnArtanhWhoseDerivativeIsARoot(Entity expr, Entity.Variable x, bool integrateByParts)
+ {
+ Entity constant = Number.Integer.One;
+ Logf? logarithm = null;
+ var power = 0;
+ foreach (var (factor, underneath) in FactorsOfTheIntegrand(expr))
+ {
+ if (!factor.ContainsNode(x))
+ {
+ constant = underneath ? constant / factor : constant * factor;
+ continue;
+ }
+ if (!underneath && logarithm is null && factor is Logf ln && ln.Base == MathS.e)
+ {
+ logarithm = ln;
+ continue;
+ }
+ if (APowerOfTheVariable(factor, x) is not { } k)
+ return null;
+ power += underneath ? -k : k;
+ }
+ if (logarithm is null || power == -1 || System.Math.Abs(power) > 24
+ || logarithm.Antilogarithm is not Divf(Sumf(var one, var u), Minusf(var alsoOne, var alsoU))
+ || one != Number.Integer.One || alsoOne != Number.Integer.One || u != alsoU)
+ return null;
+ // u read as A x/sqrt(Q): a constant, x once above the bar, and the root of Q.
+ Entity slope = Number.Integer.One;
+ Entity? radicand = null;
+ var sawX = false;
+ foreach (var (factor, underneath) in FactorsOfTheIntegrand(u))
+ {
+ if (!factor.ContainsNode(x))
+ slope = underneath ? slope / factor : slope * factor;
+ else if (factor == x && !underneath && !sawX)
+ sawX = true;
+ else if (radicand is null && factor is Powf(var @base, Number.Rational half)
+ && (underneath ? half == Number.Rational.Create(1, 2) : half == Number.Rational.Create(-1, 2)))
+ radicand = @base;
+ else
+ return null;
+ }
+ if (!sawX || radicand is null
+ || !TreeAnalyzer.TryGetPolyQuadratic(radicand, x, out var square, out var linear, out var free)
+ || !TreeAnalyzer.IsZero(linear) || TreeAnalyzer.IsZero(free) || !VanishesIdentically(slope * slope - square))
+ return null;
+ var raised = power + 1;
+ var rest = raised == 0 ? 1 / MathS.Sqrt(radicand)
+ : raised > 0 ? (raised == 1 ? x : MathS.Pow(x, raised)) / MathS.Sqrt(radicand)
+ : 1 / ((raised == -1 ? x : MathS.Pow(x, -raised)) * MathS.Sqrt(radicand));
+ if (Integration.ComputeAsAQuestionOfItsOwn(rest, x, integrateByParts) is not { } integral
+ || integral.Nodes.Any(node => node is Integralf || node == MathS.NaN))
+ return null;
+ return (constant * (MathS.Pow(x, raised) * logarithm - 2 * slope * integral) / raised).InnerSimplified;
+ }
+
///
/// A quotient by the square of a base, by parts against the base's reciprocal, where the
/// base's derivative makes the rest exact: N/(M v^2) is g v'/v^2 with
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
index f6c14bc2a..f5645285e 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
@@ -782,6 +782,8 @@ private static Entity WithItsPiecewiseSumsCombined(Entity expr)
if ((answer = IndefiniteIntegralSolver.SolveAPowerTimesAnExponentialOfAQuadraticInALogarithm(expr, x)) is { }) return answer;
// And a negative whole power of one, onto the exponential integral by t = A + B ln(c x^r).
if ((answer = IndefiniteIntegralSolver.SolveAPowerOverAPowerOfALogarithm(expr, x)) is { }) return answer;
+ // And x^m artanh(A x/sqrt(d + A^2 x^2)), by parts, the logarithm's derivative read as the root it is.
+ if ((answer = IndefiniteIntegralSolver.SolveByPartsAgainstAnArtanhWhoseDerivativeIsARoot(expr, x, integrateByParts)) is { }) return answer;
// A power of an exponential with a positive base is the exponential of the product,
// exactly, and only that spelling is one the exponential rules read.
if ((answer = IndefiniteIntegralSolver.SolveByFlatteningAPowerOfAnExponential(expr, x, integrateByParts)) is { }) return answer;
diff --git a/Sources/Tests/UnitTests/Calculus/APowerTimesAnArtanhWhoseDerivativeIsARootIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/APowerTimesAnArtanhWhoseDerivativeIsARootIntegralTest.cs
new file mode 100644
index 000000000..dbfa5fad8
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/APowerTimesAnArtanhWhoseDerivativeIsARootIntegralTest.cs
@@ -0,0 +1,53 @@
+//
+// 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^m artanh(sqrt(k) x/sqrt(d + k x^2)), whose derivative is sqrt(k)/sqrt(d + k x^2),
+ /// by parts. Differentiated as written, the logarithm is a quotient of two sums with a root in
+ /// each, and the search ran past its budget on what was left. Rubi's 7.3.7.
+ /// #233
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class APowerTimesAnArtanhWhoseDerivativeIsARootIntegralTest
+ {
+ [Theory]
+ [InlineData("atanh(x*sqrt(k)/sqrt(d + k*x^2))")]
+ [InlineData("x*atanh(x*sqrt(k)/sqrt(d + k*x^2))")]
+ [InlineData("x^4*atanh(x*sqrt(k)/sqrt(d + k*x^2))")]
+ [InlineData("atanh(x*sqrt(k)/sqrt(d + k*x^2))/x^2")]
+ [InlineData("atanh(x*sqrt(k)/sqrt(d + k*x^2))/x^5")]
+ [InlineData("atanh(x/sqrt(1 + x^2))")]
+ public void ByPartsAgainstTheRoot(string integrand)
+ {
+ var integral = integrand.ToEntity().Integrate("x");
+ var text = integral.Stringize();
+ Assert.DoesNotContain("integral(", text);
+ Entity Pinned(Entity e) => e.Substitute("d", 1.3).Substitute("k", 0.7);
+ var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
+ var original = Pinned(integrand.ToEntity());
+ var compared = 0;
+ foreach (var at in new[] { -2.1, -0.4, 0.3, 0.8, 1.3, 2.9 })
+ {
+ var want = original.Substitute("x", at).EvalNumerical();
+ var got = derivative.Substitute("x", at).EvalNumerical();
+ if (want.IsNaN)
+ continue;
+ 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) + Math.Abs((double)want.ImaginaryPart)),
+ $"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
+ }
+ Assert.True(compared >= 5, $"only {compared} points could be compared for {integrand}");
+ }
+ }
+}