Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -15149,7 +15163,7 @@ private static bool HasTheSameRatioAtTwoPoints(Entity expr, Entity reference, En
/// polynomials in <paramref name="x"/> of the same degree: the ratio of the leading
/// coefficients, where every other coefficient agrees with it once simplified.
/// </summary>
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
Expand Down Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/// <summary>
/// The radicand an inverse sine or cosine holds without writing it: <c>arcsin(u)'</c> is
/// <c>u'/sqrt(1 - u^2)</c>, so beside <c>arcsin(2x)</c> the factors <c>(3 + 6x)(5 - 10x)</c>,
/// whose product is <c>15 (1 - 4x^2)</c>, are that radicand written as two, and
/// <c>(5 - 20x^2)^(3/2)</c> a multiple of it written as one. Rubi's 5.1.4 and 5.2.4; the
/// points are inside <c>|2x| &lt; 1</c>, where every integrand here is real.
/// </summary>
[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 });

/// <summary>
/// The tangent, whose radical is <c>sqrt(1 + x^2)</c> and becomes the secant.
/// </summary>
Expand Down
Loading