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
16 changes: 16 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2200,6 +2200,22 @@ number; the zero is a power `1/x`, whose integral is a logarithm. A symbolic `b`
| `"sin(a + ln(c*x^2)*sqrt(-1/4))".ToEntity().Integrate("x")` | `integral(...)` | powers of `x` and `c x^2` and a logarithm, through `e^(i a)` |
| `"1/cos(a - 2*i*ln(c*x))^(3/2)".ToEntity().Integrate("x")` | `integral(...)` | an arctangent and a logarithm of a root, through `e^(i a)` |

### A secant or cosecant of a logarithm of an imaginary power is integrated in a named constant

**Answers where there were none.** `sec(a + 2 ln(c x^(i/2)))^3` was declined, with `x sec(a + 2 ln(c x^i))^3` and the
cosecant's, the imaginary factor being in the logarithm's power of the variable rather than its coefficient (Rubi's
4.7.5). `e^(i L)` is a constant `K` times `x^p` for the real `p = i b x u'/u`, with `K = e^(i L) x^(-p)` constant
wherever it is defined, for either sign of `c`. With `K` named the integrand is rational in `x`; the same question
asked without naming it answered a piecewise of over 6,000 characters, `c^(2 i)` and `c^(-2 i)` never cancelling
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sec(a + 2*ln(c*x^(1/2*i)))^3".ToEntity().Integrate("x")` | `integral(...)` | 262 characters |
| `"csc(a + 2*ln(c*x^(1/2*i)))^3".ToEntity().Integrate("x")` | `integral(...)` | 264 characters |
| `"x*sec(a + 2*ln(c*x^i))^3".ToEntity().Integrate("x")` | `integral(...)` | 275 characters, and so the cosecant's |
| `"sec(a + 2*ln(c/x^(1/2*i)))^3".ToEntity().Integrate("x")` | `integral(...)` | 484 characters |

### A constant plus an imaginary cosine and sine is an exponential

**Answers where there were none.** `(A + B cos(x))/(a + b cos(x) + i b sin(x))` was declined, with the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26893,8 +26893,16 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum(
{
if (!expr.Nodes.Any(node => node is Logf && node.ContainsNode(x)))
return null;
// `e^(i L)` is `K x^p` for a real `p` when `u` is a product of constants and powers of
// the variable, with `K = e^(i L) x^(-p)` constant wherever it is defined: named, the
// integrand is rational in `x` with one symbol in it, where `e^(i a)` and `e^(-i a)`, or
// `c^(2 i)` and `c^(-2 i)`, were two that never cancelled and answered a piecewise of
// thousands of characters. One argument only, so that one name stands for it.
var arguments = new HashSet<Entity>();
Entity? power = null;
var named = Variable.CreateUnique(expr, "k_exp");
var any = false;
var rewritten = expr.Replace(node =>
Entity Rewritten(bool naming) => expr.Replace(node =>
{
var (argument, kind) = node switch
{
Expand All @@ -26906,11 +26914,14 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum(
Cosecantf(var of) => (of, 5),
_ => ((Entity?)null, -1)
};
if (argument is null || !IsLinearInALogarithmWithAnImaginaryCoefficient(argument, x))
if (argument is null || !IsLinearInALogarithmWithAnImaginaryCoefficient(argument, x, out var itsPower))
return node;
any = true;
var plus = MathS.Pow(MathS.e, MathS.i * argument);
var minus = MathS.Pow(MathS.e, -MathS.i * argument);
arguments.Add(argument);
power = itsPower;
var (plus, minus) = naming && itsPower is { }
? (named * MathS.Pow(x, itsPower), MathS.Pow(x, -itsPower) / named)
: (MathS.Pow(MathS.e, MathS.i * argument), MathS.Pow(MathS.e, -MathS.i * argument));
return kind switch
{
0 => (plus - minus) / (2 * MathS.i),
Expand All @@ -26921,6 +26932,7 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum(
_ => 2 * MathS.i / (plus - minus),
};
});
var rewritten = Rewritten(naming: true);
if (!any)
return null;
// Beside its own derivative the logarithm is a substitution's: `tan(a + i ln(x))/x` is
Expand All @@ -26935,15 +26947,26 @@ private static (Entity Factor, Entity Inside)? TryTakeACommonLinearFactorOfASum(
if (beside.ContainsNode(x) && AreProportionalAtSampledPoints(beside, logarithm.Differentiate(x), x))
return null;
}
return Integration.ComputeAsTheSameQuestion(rewritten, x, integrateByParts);
// A condition on `K` is a sign of a number that is not real, and has no value once
// `K` is written back: `tan(a + i ln(x))`'s antiderivative is a piecewise on `K^4 > 0`.
// There the exponentials are asked as they are.
if (power is { } && arguments.Count == 1
&& Integration.ComputeAsTheSameQuestion(rewritten, x, integrateByParts) is { } answer
&& !answer.Nodes.Any(node => node is Providedf(_, var condition) && condition.ContainsNode(named)
|| node is Piecewise piecewise && piecewise.Cases.Any(@case => @case.Predicate.ContainsNode(named))))
return answer.Substitute(named, (MathS.Pow(MathS.e, MathS.i * arguments.First()) * MathS.Pow(x, -power)).InnerSimplified);
return Integration.ComputeAsTheSameQuestion(Rewritten(naming: false), x, integrateByParts);
}

/// <summary>
/// Whether <paramref name="argument"/> is <c>a + b ln(u)</c>, with <c>u</c> the only place the
/// variable is and <c>b</c> an imaginary number.
/// variable is and <c>b</c> an imaginary number, or <c>u</c> a product of constants and
/// powers of the variable whose powers <c>b</c> makes imaginary. <paramref name="power"/> is
/// then the real <c>p</c> of <c>e^(i L) = K x^p</c>, and null for any other <c>u</c>.
/// </summary>
private static bool IsLinearInALogarithmWithAnImaginaryCoefficient(Entity argument, Entity.Variable x)
private static bool IsLinearInALogarithmWithAnImaginaryCoefficient(Entity argument, Entity.Variable x, out Entity? power)
{
power = null;
var logarithms = argument.Nodes
.Where(node => node is Logf(var @base, var of) && @base == MathS.e && of.ContainsNode(x))
.Distinct().ToList();
Expand All @@ -26958,10 +26981,33 @@ private static bool IsLinearInALogarithmWithAnImaginaryCoefficient(Entity argume
// A number, and not a symbol's: with `b = sqrt(-1/n^2)` the power of the variable this
// leaves is `1/x` for every positive n, which nothing reading `n` symbolically can know,
// and the general power's formula comes back with a zero below its bar.
return coefficient.Vars.Count() == 0 && coefficient.Evaled is Number.Complex number && number is not Number.Real
&& System.Math.Abs((double)number.RealPart) < 1e-12 * System.Math.Abs((double)number.ImaginaryPart);
if (coefficient.Vars.Any())
return false;
// `2 ln(c x^(i/2))`: the imaginary factor is in the logarithm's power of the variable.
// What makes `e^(i b ln(u))` a power of the variable is that `b x u'/u` is a constant,
// and it is `i` there. For `u` a product of constants and powers of the variable,
// `x u'/u` is the sum of those powers, read off the factors.
Entity sum = Number.Integer.Zero;
foreach (var (factor, underneath) in FactorsOfTheIntegrand(((Logf)logarithms[0]).Antilogarithm))
{
Entity? its = factor == x ? Number.Integer.One
: factor is Powf(var @base, var exponent) && @base == x && !exponent.ContainsNode(x) ? exponent
: !factor.ContainsNode(x) ? Number.Integer.Zero
: null;
if (its is null)
return IsAnImaginaryNumber(coefficient);
sum = underneath ? sum - its : sum + its;
}
if (!IsAnImaginaryNumber(coefficient * sum))
return false;
power = (MathS.i * coefficient * sum).InnerSimplified;
return true;
}

private static bool IsAnImaginaryNumber(Entity expr)
=> expr.Vars.Count() == 0 && expr.Evaled is Number.Complex number && number is not Number.Real
&& System.Math.Abs((double)number.RealPart) < 1e-12 * System.Math.Abs((double)number.ImaginaryPart);

/// <summary>
/// A power of the variable times a sine or cosine of a logarithm, in closed form:
/// <c>int x^m sin(L) dx</c> is <c>x^(m + 1)((m + 1) sin(L) - B cos(L))/((m + 1)^2 + B^2)</c>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,33 @@ public void BesideItsOwnDerivativeByTheSubstitution(string integrand)
DifferentiatesBack(integrand, integral);
}

private static void DifferentiatesBack(string integrand, Entity integral)
/// <summary>
/// The imaginary factor in the logarithm's power of the variable, <c>2 ln(c x^(i/2))</c>:
/// <c>e^(i L)</c> is a constant <c>K</c> times <c>x^p</c> for the real <c>p = i b x u'/u</c>,
/// and with <c>K</c> named the integrand is rational in <c>x</c>. Unnamed, <c>c^(2 i)</c>
/// and <c>c^(-2 i)</c> never cancelled and the answer was a piecewise of 6,000 characters.
/// <c>K</c> is <c>e^(i L) x^(-p)</c>, constant wherever it is defined, for either sign of
/// <c>c</c>.
/// </summary>
[Theory]
[InlineData("sec(a + 2*ln(c*x^(1/2*i)))^3", 1.3)]
[InlineData("sec(a + 2*ln(c*x^(1/2*i)))^3", -1.3)]
[InlineData("csc(a + 2*ln(c*x^(1/2*i)))^3", 1.3)]
[InlineData("x*sec(a + 2*ln(c*x^i))^3", 1.3)]
[InlineData("x*csc(a + 2*ln(c*x^i))^3", -1.3)]
[InlineData("sec(a + 2*ln(c/x^(1/2*i)))^3", 1.3)]
[InlineData("sec(a + 2*ln(c/x^(1/2*i)))^3", -1.3)]
public void AnImaginaryPowerInTheLogarithm(string integrand, double c)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.True(integral.Stringize().Length <= 600, $"{integral.Stringize().Length} characters");
DifferentiatesBack(integrand, integral, c);
}

private static void DifferentiatesBack(string integrand, Entity integral, double c = 1.3)
{
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("a", 0.4).Substitute("c", 1.3);
Entity Pinned(Entity e) => e.Substitute("a", 0.4).Substitute("c", c);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in new[] { 0.3, 0.8, 1.5, 2.4 })
Expand Down
Loading