diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 5ec2f6700..fdd6a2b3b 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -231,6 +231,18 @@ It is written out again in the precision asked for now
| `Rational.Create(128, 12167)`'s `EDecimal`, read at the default precision and then under 300 digits | 100 digits | 300 digits |
| `sqrt(46) * 128/12167` evaluated under 300 digits, with that rational | relative error `4.7e-101` | correct to 300 digits |
+### A power of x times the logarithm of a polynomial plus a root is integrated by parts over the conjugate
+
+**Answers where there were none.** `x^3 ln(-1 + 4 x + 4 sqrt((x - 1) x))` was declined, and so were three more of Rubi's 3.5,
+with `x^(3/2)`, `x^(-3/2)` and `x^(-5/2)` beside the same logarithm. With `D = A^2 - B^2 Q`, the
+derivative of `ln(A + B sqrt(Q))` is `D'/(2 D) + (Q (A B' - A' B) + A B Q'/2)/(D sqrt(Q))` -- here `D = 8 x + 1` -- so by
+parts what is left is a rational function and one over the root
+([#233](https://github.com/asc-community/AngouriMath/issues/233)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"x^3*ln(-1+4*x+4*sqrt((x-1)*x))".ToEntity().Integrate("x")` | `integral(...)` | `x^4 ln(...)/4` minus a polynomial, `ln(8 x + 1)` and terms over `sqrt(x^2 - x)` |
+
### The last digits of an evaluated logarithm, exponential, real power or complex power
**Silent, and in the hundredth digit.** `ln`, `log`, `e^x`, a real base to a real power and the
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 6986f050e..ed165e985 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -442,6 +442,97 @@ private static bool IsAnInverseFunctionTimesARationalFunction(Entity expr, Entit
return inverse == 1;
}
+ ///
+ /// A power of x times the logarithm of A + B sqrt(Q), for polynomials A,
+ /// B and Q, by parts, with the logarithm's derivative written over the conjugate:
+ /// with D = A^2 - B^2 Q, it is
+ /// D'/(2 D) + (Q (A B' - A' B) + A B Q'/2)/(D sqrt(Q)), a rational function and one over
+ /// the root, which the rules for those answer. Rubi's 3.5,
+ /// x^3 ln(-1 + 4 x + 4 sqrt((x - 1) x)), where D = 8 x + 1.
+ /// https://github.com/asc-community/AngouriMath/issues/233
+ ///
+ ///
+ /// The search differentiates the logarithm as written, a quotient with the root in both
+ /// parts, and ran past the budget on what was left. Only for a D that is not a
+ /// constant: for one that is, ln(x + sqrt(x^2 + 1)) and the other inverse hyperbolic
+ /// functions, the derivative is the root's alone, and the rules for those answer them.
+ /// The derivative is an identity of the algebra, sqrt(Q)^2 = Q, with no branch in it.
+ ///
+ internal static Entity? SolveByPartsAgainstALogarithmOfARadicalSum(Entity expr, Entity.Variable x)
+ {
+ Entity constant = Number.Integer.One;
+ Logf? logarithm = null;
+ Entity power = Number.Integer.Zero;
+ 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;
+ }
+ Entity? k = factor == x ? Number.Integer.One : factor is Powf(var raisedX, Number.Rational r) && raisedX == x ? r : null;
+ if (k is null)
+ return null;
+ power = underneath ? power - k : power + k;
+ }
+ if (logarithm is null || logarithm.Antilogarithm is not (Sumf or Minusf) || power.InnerSimplified.Evaled is not Number.Rational m
+ || m == Number.Integer.MinusOne)
+ return null;
+ // The argument as A + B sqrt(Q), term by term.
+ Entity a = Number.Integer.Zero, b = Number.Integer.Zero;
+ Entity? radicand = null;
+ foreach (var term in Sumf.LinearChildren(logarithm.Antilogarithm))
+ {
+ Entity? root = null;
+ Entity rest = Number.Integer.One;
+ foreach (var factor in Mulf.LinearChildren(term))
+ {
+ if (root is null && factor is Powf(var q, Number.Rational half) && half == Number.Rational.Create(1, 2) && q.ContainsNode(x))
+ root = q;
+ else
+ rest *= factor;
+ }
+ if (root is null)
+ {
+ a += term;
+ continue;
+ }
+ if (radicand is not null && radicand != root)
+ return null;
+ radicand = root;
+ b += rest;
+ }
+ if (radicand is null
+ || !TreeAnalyzer.TryGetPolynomial(a, x, out var aRead) || aRead.Keys.Any(k => k.Sign < 0)
+ || !TreeAnalyzer.TryGetPolynomial(b, x, out var bRead) || bRead.Keys.Any(k => k.Sign < 0)
+ || !TreeAnalyzer.TryGetPolynomial(radicand, x, out var qRead) || qRead.Keys.Any(k => k.Sign < 0) || qRead.Keys.All(k => k.IsZero))
+ return null;
+ // D = A^2 - B^2 Q, and the numerator over the root, as polynomials.
+ Entity Written(Entity polynomial) => TreeAnalyzer.TryGetPolynomial(polynomial, x, out var read)
+ ? read.Where(monomial => monomial.Value.InnerSimplified.Evaled is not Number.Complex { IsZero: true })
+ .Aggregate((Entity)Number.Integer.Zero, (sum, monomial) => sum + monomial.Value.InnerSimplified * (monomial.Key.IsZero ? Number.Integer.One : monomial.Key.Equals(EInteger.One) ? x : MathS.Pow(x, Number.Integer.Create(monomial.Key))))
+ : polynomial;
+ var d = Written(a * a - b * b * radicand);
+ if (!TreeAnalyzer.TryGetPolynomial(d, x, out var dRead) || dRead.Keys.All(k => k.IsZero) || d == Number.Integer.Zero)
+ return null;
+ var (da, db, dq) = (a.Differentiate(x), b.Differentiate(x), radicand.Differentiate(x));
+ var overTheRoot = Written(radicand * (a * db - da * b) + a * b * dq / 2);
+ var raised = (m + 1).InnerSimplified;
+ Entity xRaised = raised == Number.Integer.One ? x : MathS.Pow(x, raised);
+ var rational = xRaised * Written(d.Differentiate(x)) / (2 * d);
+ var radical = xRaised * overTheRoot / (d * MathS.Sqrt(radicand));
+ if (Integration.ComputeAsAQuestionOfItsOwn(rational, x, integrateByParts: true) is not { } first
+ || Integration.ComputeAsAQuestionOfItsOwn(radical, x, integrateByParts: true) is not { } second
+ || first.Nodes.Concat(second.Nodes).Any(node => node is Integralf || node == MathS.NaN))
+ return null;
+ return (constant * (xRaised * logarithm - first - second) / raised).InnerSimplified;
+ }
+
///
/// An integrand that is a constant multiple of D'/D for a sum D below the
/// bar holding a root, decided at sampled points and answered as that multiple of
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
index 2f5e7b9b9..22dc0dac3 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
@@ -787,6 +787,8 @@ private static Entity WithItsPiecewiseSumsCombined(Entity expr)
// A power of a quotient of linears beside whole powers of them, which is how e^(n acoth(a x))
// over a power of c - a^2 c x^2 arrives folded, under t = the quotient.
if ((answer = IndefiniteIntegralSolver.SolveByTheMoebiusSubstitutionOfAQuotientOfLinears(expr, x)) is { }) return answer;
+ // And a power of x times the logarithm of A + B sqrt(Q), by parts, its derivative over the conjugate.
+ if ((answer = IndefiniteIntegralSolver.SolveByPartsAgainstALogarithmOfARadicalSum(expr, x)) 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/APowerTimesALogarithmOfARadicalSumIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/APowerTimesALogarithmOfARadicalSumIntegralTest.cs
new file mode 100644
index 000000000..155ef7a9b
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/APowerTimesALogarithmOfARadicalSumIntegralTest.cs
@@ -0,0 +1,50 @@
+//
+// 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 power of x times ln(A + B sqrt(Q)), by parts, with the logarithm's derivative written
+ /// over the conjugate, D = A^2 - B^2 Q: a rational function plus one over the root. The
+ /// search differentiated it as written and ran past its budget. Rubi's 3.5.
+ /// #233
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class APowerTimesALogarithmOfARadicalSumIntegralTest
+ {
+ [Theory]
+ [InlineData("ln(-1 + 4*x + 4*sqrt((x - 1)*x))")]
+ [InlineData("x^3*ln(-1 + 4*x + 4*sqrt((x - 1)*x))")]
+ [InlineData("x*ln(2*x + sqrt(x^2 + 3))")]
+ public void ByPartsOverTheConjugate(string integrand)
+ {
+ var integral = integrand.ToEntity().Integrate("x");
+ var text = integral.Stringize();
+ Assert.DoesNotContain("integral(", text);
+ var derivative = integral.Substitute("C", 0).Differentiate("x");
+ var original = integrand.ToEntity();
+ var compared = 0;
+ // Where the root is real and the logarithm's argument positive.
+ foreach (var at in new[] { 1.2, 1.7, 2.3, 3.1, 4.4, 6.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}");
+ }
+ }
+}