diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 590cd4f7e..7b1c16722 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -1425,6 +1425,25 @@ with `K = sqrt(L1) sqrt(L2)/sqrt(M)` in front of the answer, constant wherever i
Rubi's 7.1.4 and 7.1.5, all 376 problems that count: 308 to 345, no row lost, 56 timeouts to 27.
+### The radicand an inverse sine or cosine holds is read as one
+
+`(d + c d x)^(1/2) (f - c f x)^(3/2) (a + b arcsin(c x))` ran out of time. `arcsin(u)` holds a
+radicand without writing it -- its derivative is `u'/sqrt(1 - u^2)` -- so beside `arcsin(c x)`
+the factors `d + c d x` and `f - c f x`, whose product is `d f (1 - c^2 x^2)`, are the case of the
+two entries above with `1 - c^2 x^2` for the radicand. That radicand is now read from an inverse
+sine or cosine of a linear, and two factors whose product is the radicand itself -- `sqrt(1 + c x)
+sqrt(1 - c x)` beside `arccos(c x)` -- are written as its one root too. A single base that is a
+multiple of it, `(d - c^2 d x^2)^(3/2)`, is written over it the same way, with
+`K = sqrt(d - c^2 d x^2)/sqrt(1 - c^2 x^2)` in front, which is `sqrt(d)` for a positive `d`.
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"(d+c*d*x)^(1/2)*(f-c*f*x)^(3/2)*(a+b*asin(c*x))".Integrate("x")` | left unevaluated | in `arcsin(c x)` and `1 - c^2 x^2`, with `K` in front |
+| `"(d-c^2*d*x^2)^(3/2)*(a+b*asin(c*x))".Integrate("x")` | left unevaluated | the same |
+
+Rubi's 5.1.4, 5.1.5, 5.2.4 and 5.2.5, all 504 problems that count: 405 to 463, no row lost, 77
+timeouts to 19.
+
### `binomial(n, k)` is a function
**Addition, not silent.** The binomial coefficient is a node, `Entity.Binomialf`, spelled
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 3a7bfbbec..9dd36ac1a 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -14992,6 +14992,17 @@ static bool Through(Entity node, Entity.Variable x)
&& radicand.ContainsNode(x) && TreeAnalyzer.TryGetPolynomial(radicand, x, out var read) && read.Keys.Max() >= EInteger.One
&& !references.Contains(radicand))
references.Add(radicand);
+ // And the radicand an inverse sine or cosine of a linear holds without writing it:
+ // `arcsin(u)'` is `u'/sqrt(1 - u^2)`, so `(d + c d x)^(1/2) (f - c f x)^(3/2)` beside
+ // `arcsin(c x)` is the same case as beside `arcosh`, with `1 - c^2 x^2` for the radicand.
+ foreach (var node in expr.Nodes)
+ if (node switch { Arcsinf(var inner) => inner, Arccosf(var inner) => inner, _ => null } is { } argument
+ && argument.ContainsNode(x) && TreeAnalyzer.TryGetPolyLinear(argument, x, out _, out _))
+ {
+ var radicand = (1 - MathS.Sqr(argument)).Expand().InnerSimplified;
+ if (!references.Contains(radicand))
+ references.Add(radicand);
+ }
if (references.Count == 0)
return null;
var multiple = Variable.CreateUnique(expr, "k_rad");
@@ -15078,7 +15089,10 @@ private static bool TryWriteAPairOfLinearsOverARadicand(Entity expr, Entity.Vari
var product = (first * second).Expand();
foreach (var candidate in references)
{
- if (TryReadAsAConstantMultiple(product, candidate, x) is not { } lambda)
+ // A multiple of one counts here, where it does not for a single base: two
+ // factors whose product *is* the radicand -- `sqrt(1 + c x) sqrt(1 - c x)`
+ // beside `arcsin(c x)` -- still want writing as its one root.
+ if (TryReadAsAConstantMultiple(product, candidate, x, allowOne: true) is not { } lambda)
continue;
Entity together;
if (half is Number.Integer)
@@ -15149,7 +15163,7 @@ private static bool HasTheSameRatioAtTwoPoints(Entity expr, Entity reference, En
/// polynomials in of the same degree: the ratio of the leading
/// coefficients, where every other coefficient agrees with it once simplified.
///
- private static Entity? TryReadAsAConstantMultiple(Entity expr, Entity reference, Entity.Variable x)
+ private static Entity? TryReadAsAConstantMultiple(Entity expr, Entity reference, Entity.Variable x, bool allowOne = false)
{
// Read as written, or simplified first: the normalisation makes a power of a
// polynomial with a symbolic leading coefficient monic and writes the constant term as
@@ -15178,7 +15192,7 @@ private static bool HasTheSameRatioAtTwoPoints(Entity expr, Entity reference, En
var lambda = (leading / theirs[top]).InnerSimplified;
if (lambda.Vars.Any())
lambda = Functions.PartialFractions.Bare(lambda.Simplify());
- if (lambda.Evaled is Number.Complex { IsZero: true } || lambda == Number.Integer.One)
+ if (lambda.Evaled is Number.Complex { IsZero: true } || lambda == Number.Integer.One && !allowOne)
return null;
foreach (var pair in theirs)
{
diff --git a/Sources/Tests/UnitTests/Calculus/InverseTrigonometricSubstitutionTest.cs b/Sources/Tests/UnitTests/Calculus/InverseTrigonometricSubstitutionTest.cs
index c9a11c82f..6b990befe 100644
--- a/Sources/Tests/UnitTests/Calculus/InverseTrigonometricSubstitutionTest.cs
+++ b/Sources/Tests/UnitTests/Calculus/InverseTrigonometricSubstitutionTest.cs
@@ -80,6 +80,22 @@ private static void DifferentiatesBack(string integrand, double[] points)
[InlineData("x^3*arcsin(x)/(1 - x^2)^(3/2)")]
public void TheSineAndTheCosine(string integrand) => DifferentiatesBack(integrand, InsideTheUnitInterval);
+ ///
+ /// The radicand an inverse sine or cosine holds without writing it: arcsin(u)' is
+ /// u'/sqrt(1 - u^2), so beside arcsin(2x) the factors (3 + 6x)(5 - 10x),
+ /// whose product is 15 (1 - 4x^2), are that radicand written as two, and
+ /// (5 - 20x^2)^(3/2) a multiple of it written as one. Rubi's 5.1.4 and 5.2.4; the
+ /// points are inside |2x| < 1, where every integrand here is real.
+ ///
+ [Theory]
+ [InlineData("sqrt(3 + 6*x)*(5 - 10*x)^(3/2)*(1 + arcsin(2*x))")]
+ [InlineData("x*(1 + arcsin(2*x))^2/(sqrt(3 + 6*x)*sqrt(5 - 10*x))")]
+ [InlineData("(3 + 6*x)^(3/2)*(1 + arcsin(2*x))/(5 - 10*x)^(3/2)")]
+ [InlineData("(5 - 20*x^2)^(3/2)*(1 + arcsin(2*x))")]
+ [InlineData("sqrt(1 + 2*x)*sqrt(1 - 2*x)*(1 + arccos(2*x))")]
+ public void TheRadicandOfAnInverseSineOrCosine(string integrand)
+ => DifferentiatesBack(integrand, new[] { -0.4, -0.1, 0.2, 0.35, 0.45 });
+
///
/// The tangent, whose radical is sqrt(1 + x^2) and becomes the secant.
///