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
18 changes: 18 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,24 @@ interval between the poles of the tangent, as the substitution's are
| `"(A + B*tan(x))/(a + i*a*tan(x))^2".ToEntity().Integrate("x")` | `integral(...)` | the same |
| `"1/(a + i*a*tan(c + d*x))^3".ToEntity().Integrate("x")` | `integral(...)` | the same in `tan(c + d x)` |

### An integrand with the imaginary unit in it is not simplified by the rule that scales the variable

**Answers where there were none.** The rule that scales the variable by the integrand's one symbol
simplified the scaled integrand three times, to separate the whole power of the scale it is
homogeneous of. With the imaginary unit beside the symbol that search ran past any budget: on the
unreleased master `((1 + i a x)/(1 - i a x))^(-5/4)/x^2` took more than two minutes to be declined,
and the rules after this one never had their turn on integrands that it held up. Such an integrand is
inner-simplified now, and declined in seconds where the parts do not separate
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sec(c + d*x)^3/(a + i*a*tan(c + d*x))".ToEntity().Integrate("x")` | `integral(...)` | logarithms of `tan((c + d x)/2) ± 1` and a quotient |
| `"tan(c + d*x)^(8/3)/(a + i*a*tan(c + d*x))".ToEntity().Integrate("x")` | `integral(...)` | an antiderivative in `tan(c + d x)^(1/3)` |
| `"1/(a + b*csc(c + d*x)^2)^4".ToEntity().Integrate("x")` | `integral(...)` | an antiderivative, by the signs of `a` and `b` |
| `"x^4*e^(2*i*atan(a + b*x))".ToEntity().Integrate("x")` | `integral(...)` | a polynomial, logarithms and arctangents of `a + b x` |
| `"sec(c + d*x)^2/(a + i*a*tan(c + d*x))".ToEntity().Integrate("x")` | `ln(i a d tan(c + d x) + a d)/(i a d)` | `ln(i tan(c + d x) + 1)/(i a d)`, the same up to a constant |

### `NaN` was returned as the antiderivative of something that has one

**A wrong answer, not a missing one.** `1/(a*x^2)` came back as `NaN + C`, and `NaN` is this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18538,7 +18538,13 @@ bool IsAConstantTimesAPowerOfOneMinusUSquared(Entity polynomial, out Entity cons

// dx = c dt.
var t = Variable.CreateUnique(expr, "u_scale");
var scaled = (expr.Substitute(x, scale * t) * scale).Simplify();
// With the imaginary unit in the integrand the simplifier's search beside the symbol
// does not end within any budget, and inner simplification separates what a whole
// power of the scale does: `((1 + i a x)/(1 - i a x))^(-5/4)/x^2` under its radical's
// substitution was minutes here before it was declined. Where the parts do not
// separate so, the check below declines it.
Entity Simplified(Entity e) => HoldsTheImaginaryUnit(expr) ? Functions.PartialFractions.Bare(e.InnerSimplified) : e.Simplify();
var scaled = Simplified(expr.Substitute(x, scale * t) * scale);
if (scaled.ContainsNode(x))
return null;

Expand All @@ -18547,11 +18553,11 @@ bool IsAConstantTimesAPowerOfOneMinusUSquared(Entity polynomial, out Entity cons
// The integrand with the scale set to one is the candidate h(t), and what is left
// over when the scaled integrand is divided by it is the candidate factor. Read off
// rather than searched for: if the two do separate, the quotient *is* the factor.
var withoutScale = scaled.Substitute(scale, Number.Integer.One).Simplify();
var withoutScale = Simplified(scaled.Substitute(scale, Number.Integer.One));
if (withoutScale.ContainsNode(scale) || withoutScale == Number.Integer.Zero)
return null;

var factor = (scaled / withoutScale).Simplify();
var factor = Simplified(scaled / withoutScale);
// Collapsing the quotient attaches the condition that the denominator it cleared is
// non-zero. That denominator is the integrand's own, so the condition says where the
// integrand is defined and nothing about this rewrite; it is dropped for the same
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,20 @@ private static void DifferentiatesBack(string integrand)
[InlineData("(A + B*tan(x))/(a + i*a*tan(x))^2")]
[InlineData("1/(a + i*a*tan(c + d*x))^3")]
public void APowerOfAPlusIATangent(string integrand) => DifferentiatesBack(integrand);

/// <summary>
/// A power of a quotient of linears with the imaginary unit in it, beside a power of x the
/// substitution for it does not take down to something answered: declined, and within a
/// minute. The scaling of the variable simplified it with the symbol beside the imaginary
/// unit, and that ran past two minutes before the decline.
/// </summary>
[Theory]
[InlineData("((1 + i*a*x)/(1 - i*a*x))^(-5/4)/x^2")]
[InlineData("((1 + i*a*x)/(1 - i*a*x))^(-5/4)/x^3")]
public void AnImaginaryMobiusPowerIsDeclinedWithinAMinute(string integrand)
{
var integrating = System.Threading.Tasks.Task.Run(() => integrand.ToEntity().Integrate("x"));
Assert.True(integrating.Wait(TimeSpan.FromSeconds(60)), $"{integrand} was not settled within a minute");
}
}
}
Loading