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 @@ -412,6 +412,22 @@ shorter than the symbolic split's.
| `"1/(u*(u^2 + 1)^6*(a*(u^2 + 1) + 2*a*u))".Integrate("u")` | unevaluated | `(17/24 - 829/1536 u + … - 273/512 u^10)/(a (u^2 + 1)^5 (u + 1)) + ln(u)/a - 7/64 ln(u + 1)/a - 57/128 ln(u^2 + 1)/a - 329/512 arctan(u)/a` |
| `"u^5/((u^2 - 1)^5*(2*a*u + b*(u^2 + 1)))".Integrate("u")` | unevaluated | the same piecewise in `u`, its coefficients `1/256 (3a^3 - 7ab^2)/(a^4 - 2a^2 b^2 + b^4)` and the like rather than two thousand nodes each |

### A logarithm of a nested quotient is written over one bar under the exponential substitution

**Improvement, not silent.** `atanh(tanh(a + b x))` reaches the integrator as
`1/2 ln((1 + (w - 1)/(w + 1))/(1 - (w - 1)/(w + 1)))` in `w = e^(2(a + b x))`, and under `u = w`
that logarithm is `1/2 ln(u)`; but the combining on the way into the substitution reaches the
quotient the integrand is and not one inside a function, the simplifier combines nothing (#1239),
and the substitution search compared its candidates against the nested spelling and never saw
the `u`. A logarithm whose argument is a rational function of `u` with a quotient nested in it is
now written over one bar in lowest terms, where that is smaller, before the question in `u` is
asked. Only under that substitution; `Simplify` still combines nothing.

| | Was | Is |
|---|---|---|
| `"1/sqrt(atanh(tanh(a + b*x)))".Integrate("x")` | unevaluated after 49 s | `2 (1/2 ln(e^(2 b x + 2 a)))^(1/2)/(1/2)/(2 b)`, 0.3 s |
| `"atanh(tanh(a + b*x))^(1/2)".Integrate("x")` | unevaluated | `2 (1/2 ln(e^(2 b x + 2 a)))^(3/2)/(3/2)/(2 b)` |

### A condition the answer states on its own is no longer repeated beside it

**Improvement, not silent.** `Simplify` returned `(1 - ln(x))/x^2 provided not x = 0` for the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9828,6 +9828,7 @@ node is Powf(Powf(var @base, var inner), var outer)
rewritten / (Number.Rational.Create(k) * u)).Simplify();
if (integrand is Providedf(var inner, _))
integrand = inner;
integrand = WithLogarithmArgumentsOverOneBar(integrand, u);
// A whole power of a product is written as the product of the powers: the
// simplifier writes `4a^2 u^2` as `(a u)^2 4`, and no rational reader sees the `u^2`
// inside -- Timofeev's `1/(a^2 + b^2 cosh(x)^2)` was declined in that spelling and
Expand Down Expand Up @@ -9879,6 +9880,40 @@ node is Powf(Powf(var @base, var inner), var outer)
}
}

/// <summary>
/// <paramref name="expr"/> with every logarithm whose argument is a rational function
/// of <paramref name="x"/> with a quotient nested inside it written over one bar in
/// lowest terms, where that is smaller: <c>ln((1 + (u - 1)/(u + 1))/(1 - (u - 1)/(u + 1)))</c>
/// is <c>ln(u)</c>.
/// </summary>
/// <remarks>
/// The combining above reaches the quotient the integrand is and not one inside a
/// function, and the simplifier combines nothing
/// (https://github.com/asc-community/AngouriMath/issues/1239). <c>atanh(tanh(a + b x))</c>
/// arrives as half that logarithm of <c>tanh</c> written in <c>e^(2(a + b x))</c>, and
/// under <c>u</c> the substitution search compared its candidates against the nested
/// spelling and never saw the <c>u</c> it is: <c>1/sqrt(atanh(tanh(a + b x)))</c> was
/// answered before the substitution took a symbolic slope and not after.
/// https://github.com/asc-community/AngouriMath/issues/718
/// </remarks>
private static Entity WithLogarithmArgumentsOverOneBar(Entity expr, Entity.Variable x)
=> expr.Replace(node =>
{
if (node is not Logf(var logBase, var argument) || logBase != MathS.e || !argument.ContainsNode(x) || !IsARationalFunction(argument, x)
|| !argument.Nodes.Any(inner => inner is Divf && inner != argument))
return node;
var (above, below) = Functions.SingleQuotient.Of(argument);
var over = below == Number.Integer.One ? above.InnerSimplified
: Functions.PolynomialGcd.TryCancel(above.InnerSimplified, below.InnerSimplified, out var cancelled)
? Functions.PartialFractions.Bare(cancelled).InnerSimplified
: (above / below).InnerSimplified;
if (over.Complexity >= argument.Complexity)
return node;
// Small by now, and `2u/2` is what the cancellation leaves of `(2u/(u + 1))/(2/(u + 1))`.
over = Functions.PartialFractions.Bare(over.Simplify());
return MathS.Ln(over);
});

/// <summary>
/// A product with a whole negative power of a polynomial in <paramref name="x"/> of
/// two or more terms among its factors, with every such power written below the bar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,22 @@ public void BasesThatArePowersOfOne(string integrand)
public void ASymbolicSlope(string integrand)
=> DifferentiatesBackWithParametersPinned(integrand, new[] { -0.5, 0.23, 0.61, 1.05, 1.7 });

/// <summary>
/// A logarithm's argument that is a rational function of <c>u</c> with a quotient
/// nested in it is written over one bar in lowest terms: <c>atanh(tanh(a + b x))</c>
/// arrives as <c>1/2 ln((1 + (u - 1)/(u + 1))/(1 - (u - 1)/(u + 1)))</c> under
/// <c>u = e^(2(a + b x))</c>, which is <c>1/2 ln(u)</c>, and the substitution search
/// compared its candidates against the nested spelling and never saw it. The
/// combining on the way in reaches the quotient the integrand is and not one inside a
/// function, and the simplifier combines nothing.
/// </summary>
[Theory]
[InlineData("1/sqrt(atanh(tanh(a + b*x)))")]
[InlineData("atanh(tanh(a + b*x))^(1/2)")]
[InlineData("1/atanh(tanh(a + b*x))^2")]
public void ALogarithmOfANestedQuotientIsWrittenOverOneBar(string integrand)
=> DifferentiatesBackWithParametersPinned(integrand, new[] { -0.5, 0.23, 0.61, 1.05, 1.7 });

/// <summary>
/// A quotient the gathering on the chain's entry writes as a product with a negative
/// power -- <c>u^3/((a u^2 + b)^3 u)</c> as <c>u^2 (a u^2 + b)^(-3)</c> -- is written
Expand Down
Loading