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
13 changes: 13 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,19 @@ wherever the cosine is negative; they are answered with the rest now
| `"sqrt(c*sec(x))*sqrt(a + i*a*tan(x))".ToEntity().Integrate("x")` | `integral(...)` | the integrand times an antiderivative in `e^(i x/2)` over its derivative |
| `"(c*sec(x))^(5/2)/(a + i*a*tan(x))^(5/2)".ToEntity().Integrate("x")` | `integral(...)` | the integrand times a power of `e^(i x)` |

### A symbolic power of `a + i a tan` beside a power of the secant is integrated as an exponential

**Answers where there were none.** `(k sec(c + d x))^(-4 - n) (a + i a tan(c + d x))^n` and the rest
of Rubi's 4.3.1.2 whose two powers are symbols adding up to a whole number were declined: the powers
were read as numbers only. In `w = e^(i z)` the integral is a power of `w` beside a whole power of
`w^2 + 1`, a sum of powers of `w`
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"(k*sec(c + d*x))^(-4 - n)*(a + i*a*tan(c + d*x))^n".ToEntity().Integrate("x")` | `integral(...)` | the integrand times powers of `e^(i (c + d x))` from `n - 4` to `n + 4`, each over its exponent |
| `"(a + i*a*tan(c + d*x))^n/(k*sec(c + d*x))^n".ToEntity().Integrate("x")` | `integral(...)` | the integrand over `i d n` |

### A rational function of the tangent beside a power of `a + i a tan` is integrated in that sum

**Answers where there were none.** `(A + B tan(c + d x))/sqrt(a + i a tan(c + d x))` and the rest of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26574,7 +26574,9 @@ bool ARootOfTheTangent(Entity node)
/// cosine is positive, and was declined, with every other power of the pair whose exponents
/// add up to a whole number: a root of a sum with the imaginary unit in it beside a root of the
/// secant is read by no rule, and <c>e^(i x/2)/cos(x)</c>, what the positive sums leave, is
/// declined as well. Rubi's 4.3.1.2.
/// declined as well. Rubi's 4.3.1.2. A symbol for the powers is read too:
/// <c>(pe sec(z))^(-4 - n) (a + i a tan(z))^n</c> adds up to -4, and the integral in <c>w</c>
/// is <c>w^(n - 5) (w^2 + 1)^4</c>, a sum of powers.
/// </para>
/// <para>
/// The constant is not written: the answer is the integrand times the antiderivative in
Expand All @@ -26591,7 +26593,7 @@ bool ARootOfTheTangent(Entity node)
return null;
Entity? argument = null;
var plus = false;
Number.Rational? tangentPower = null, secantPower = null;
Entity? tangentPower = null, secantPower = null;
Entity constant = Number.Integer.One;
Entity varying = Number.Integer.One;
foreach (var (factor, underneath) in FactorsOfTheIntegrand(expr))
Expand All @@ -26602,11 +26604,13 @@ bool ARootOfTheTangent(Entity node)
continue;
}
varying = underneath ? varying / factor : varying * factor;
var (@base, power) = factor is Powf(var b, var p) && p.Evaled is Number.Rational r
? (b, r)
: (factor, (Number.Rational)Number.Integer.One);
// A number or a symbol for the power: `(pe sec(z))^(-4 - n) (a + i a tan(z))^n`
// adds up to a whole number all the same.
var (@base, power) = factor is Powf(var b, var p) && !p.ContainsNode(x)
? (b, p.Evaled is Number.Rational r ? r : p)
: (factor, (Entity)Number.Integer.One);
if (underneath)
power = (Number.Rational)(-power);
power = power is Number.Rational numeric ? -numeric : (-power).InnerSimplified;
if (TryReadAnImaginaryTangent(@base, x, out var tangentOf, out var isPlus))
{
if (tangentPower is not null || argument is not null && argument != tangentOf)
Expand All @@ -26627,22 +26631,34 @@ bool ARootOfTheTangent(Entity node)
}
if (tangentPower is null || secantPower is null || argument is null
|| tangentPower is Number.Integer && secantPower is Number.Integer
|| (tangentPower + secantPower) is not Number.Integer { EInteger: var whole } || !whole.CanFitInInt32()
|| SumOfThePowers(tangentPower, secantPower) is not Number.Integer { EInteger: var whole } || !whole.CanFitInInt32()
|| !TreeAnalyzer.TryGetPolyLinear(argument, x, out var slope, out _) || TreeAnalyzer.IsZero(slope))
return null;
var k = whole.ToInt32Checked();
var phase = plus ? tangentPower : (Number.Rational)(-tangentPower);
var phase = plus ? tangentPower : (-tangentPower).InnerSimplified;
// In w = e^(i z): sec(z)^k e^(i n z) dz is (2 w)^k (w^2 + 1)^(-k) w^(n - 1) dw / i.
var w = Variable.CreateUnique(expr, "w_exp");
var inW = k >= 0
// At k = 0 the power of w alone: `(w^2 + 1)^0` is 1 only where `w^2 + 1` is not 0, and
// the integral of `w^(n - 1)` with that condition beside it was declined.
var inW = k == 0
? MathS.Pow(w, (phase - 1).InnerSimplified)
: k > 0
? MathS.Pow(2, k) * MathS.Pow(w, (phase + k - 1).InnerSimplified) / MathS.Pow(MathS.Sqr(w) + 1, k)
: MathS.Pow(2, k) * MathS.Pow(MathS.Sqr(w) + 1, -k) * MathS.Pow(w, (phase + k - 1).InnerSimplified);
if (Integration.ComputeAsAQuestionOfItsOwn(inW.InnerSimplified, w, integrateByParts) is not { } inWAnswer
|| inWAnswer.Nodes.Any(node => node == MathS.NaN))
return null;
// A short sum of symbols simplified, which the power rule leaves as it wrote it:
// `w^(n + -4 - 1 + 1)/(n + -4 - 1 + 1)` is `w^(n - 4)/(n - 4)`.
inWAnswer = inWAnswer.Replace(node => node is Sumf or Minusf && !node.ContainsNode(w) && node.Vars.Any() && node.Complexity <= 20
? node.Simplify() : node);
var exponential = MathS.Pow(MathS.e, MathS.i * argument);
var differentiatesBackTo = MathS.Pow(MathS.Sec(argument), k) * MathS.Pow(exponential, phase);
return constant * varying * inWAnswer.Substitute(w, exponential) / (MathS.i * slope * differentiatesBackTo);

// `n + (-4 - n)` is -4, which the inner simplification leaves as written.
static Entity SumOfThePowers(Entity first, Entity second)
=> (first + second).InnerSimplified is var sum && (sum is Number || sum.Complexity > 40) ? sum : sum.Simplify();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ namespace AngouriMath.Tests.Calculus
/// the real line, so the integrand is a constant on every interval where it is continuous times
/// a power of the secant and an exponential. Rubi's 4.3.1.2. The integrands are complex along
/// the real line and are compared as complex numbers, where the cosine is negative as well,
/// which is where the fourth row's answer on master was off by a constant factor.
/// which is where the fourth row's answer on master was off by a constant factor. A symbol
/// for the powers, adding up to a whole number, as well.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
Expand All @@ -29,12 +30,16 @@ public sealed class ImaginaryTangentBesideTheSecantIntegralTest
[InlineData("(a + i*a*tan(x))^(3/2)/(k*sec(x))^(7/2)")]
[InlineData("(k*sec(x))^(5/2)/(a + i*a*tan(x))^(5/2)")]
[InlineData("(k*sec(c + d*x))^(3/2)*(a - i*a*tan(c + d*x))^(3/2)")]
// A symbol for the powers, adding up to -4, -1 and 0.
[InlineData("(k*sec(c + d*x))^(-4 - n)*(a + i*a*tan(c + d*x))^n")]
[InlineData("(k*sec(c + d*x))^(-1 - n)*(a + i*a*tan(c + d*x))^n")]
[InlineData("(a + i*a*tan(c + d*x))^n/(k*sec(c + d*x))^n")]
public void AsTheExponentialItIs(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Assert.DoesNotContain("NaN", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("k", 0.8).Substitute("c", 0.4).Substitute("d", 1.1);
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("k", 0.8).Substitute("c", 0.4).Substitute("d", 1.1).Substitute("n", 0.6);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
var compared = 0;
Expand Down
Loading