Skip to content
Closed
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 @@ -351,6 +351,19 @@ a second now, as 114, which carry a factor `(1/c)^(-2)/c^2` that is 1.
| `"e^(a+b*x+c*x^2)*(b+2*c*x)/(a+b*x+c*x^2)^3".ToEntity().Integrate("x")` | `integral(...)` | 197 characters |
| `"e^(a+b*x+c*x^2)*(b+2*c*x)/(a+b*x+c*x^2)^2".ToEntity().Integrate("x")` | `integral(...)` | 114 characters |

### A power with x in its base and its exponent is read by the Risch-Norman ansatz as an exponential

**Answers where there were none.** Rubi's 2.3 `x^(-2 - 1/x) (1 - ln(x))` is `(-x^(-1/x))'`, and was declined, where
`e^(-ln(x)/x) (1 - ln(x))/x^2` was answered by the Risch-Norman ansatz at once. `B^E` is `e^(E ln(B))` on the principal
branch, which is what the power means. With the part of the exponent free of x kept as a power of `B`, the ansatz
now reads it so, and the answer is written back as a power, its factors written on both sides of the bar cancelled
([#233](https://github.com/asc-community/AngouriMath/issues/233)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"x^(-2-1/x)*(1-ln(x))".ToEntity().Integrate("x")` | `integral(...)` | `-x^(-1/x)`, 17 characters |
| `"x^(-1/x)*(1-ln(x))/x^2".ToEntity().Integrate("x")` | `integral(...)` | 19 characters |

### A power of a sum beside its derivative is read with the logarithms in it as factors

**Answers where there were none.** `(a m x^m + b n q ln(c x^n)^(q - 1))/(x (a x^m + b ln(c x^n)^q))` was declined, and so
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21050,6 +21050,42 @@ private static bool AreProportionalAtSampledPoints(Entity left, Entity right, En
{
if (!Integration.AnsweringTheQuestionAsked)
return null;
// A power with x in its base and its exponent, `B^E`, is `e^(E ln(B))` on the principal
// branch, which is what the power means, and so a monomial of the tower: Rubi's 2.3
// `x^(-2 - 1/x) (1 - ln(x))` is `(-x^(-1/x))'`, and written so it was declined, where
// `e^(-ln(x)/x) (1 - ln(x))/x^2` is answered at once.
if (expr.Nodes.Any(node => node is Powf(var b, var p) && b != MathS.e && b.ContainsNode(x) && p.ContainsNode(x)))
{
// The part of the exponent free of x stays a power of B: `x^(-2 - 1/x)` is
// `x^(-2) e^(-ln(x)/x)`, a rational function of x times the monomial, which the ansatz
// reads where `e^((-2 - 1/x) ln(x))` is a monomial it has no polynomial in x beside.
var asExponentials = expr.Replace(node =>
{
if (node is not Powf(var b, var p) || b == MathS.e || !b.ContainsNode(x) || !p.ContainsNode(x))
return node;
Entity constantPart = Number.Integer.Zero, variablePart = Number.Integer.Zero;
foreach (var term in Sumf.LinearChildren(p))
if (term.ContainsNode(x))
variablePart = variablePart == Number.Integer.Zero ? term : variablePart + term;
else
constantPart = constantPart == Number.Integer.Zero ? term : constantPart + term;
var exponential = MathS.Pow(MathS.e, (variablePart * MathS.Ln(b)).InnerSimplified);
return constantPart == Number.Integer.Zero ? exponential : MathS.Pow(b, constantPart) * exponential;
});
// And written back: `e^(q ln(B))` is `B^q` again, as the integrand had it.
return SolveByRischNormanAnsatzAsWritten(asExponentials, x) is { } inExponentials
&& inExponentials.Replace(node => node is Powf(var e0, Mulf(var q, Logf(var lb, var b))) && e0 == MathS.e && lb == MathS.e && b.ContainsNode(x)
? MathS.Pow(b, q) : node).InnerSimplified is var writtenBack
&& Functions.SingleQuotient.Of(Functions.SingleQuotient.Combine(writtenBack)) is var (top, bottom)
// A factor written on both sides of the bar, `-x x^(-1/x)/x`, cancelled.
&& CancelCommonFactors(top, bottom) is var answer
&& Functions.PartialFractions.DerivativeHoldsAtSampledPoints(answer, expr, x) ? answer : null;
}
return SolveByRischNormanAnsatzAsWritten(expr, x);
}

private static Entity? SolveByRischNormanAnsatzAsWritten(Entity expr, Entity.Variable x)
{
// The transcendental monomials: every exponential and natural logarithm of
// something in x, innermost first, each read in the indeterminates of the ones
// inside it.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
// Website: https://am.angouri.org.
//

using System;
using AngouriMath.Extensions;
using Xunit;

namespace AngouriMath.Tests.Calculus
{
/// <summary>
/// A power with the variable in its base and its exponent read by the Risch-Norman ansatz as the
/// exponential it means, <c>B^E = e^(E ln(B))</c>, the part of the exponent free of x kept as a power:
/// Rubi's 2.3 <c>x^(-2 - 1/x) (1 - ln(x))</c> is <c>(-x^(-1/x))'</c>, and as written it was declined.
/// <a href="https://github.com/asc-community/AngouriMath/issues/233">#233</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class APowerWithTheVariableInItsExponentForTheRischNormanAnsatzIntegralTest
{
[Theory]
[InlineData("x^(-2 - 1/x)*(1 - ln(x))")]
[InlineData("x^(-1/x)*(1 - ln(x))/x^2")]
public void IsAnsweredAsAPower(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
var text = integral.Stringize();
Assert.DoesNotContain("integral(", text);
Assert.True(text.Length < 40, $"the antiderivative of {integrand} is {text}");
var derivative = integral.Substitute("C", 0).Differentiate("x");
var original = integrand.ToEntity();
foreach (var at in new[] { 0.3, 0.7, 1.3, 2.2, 3.1 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).EvalNumerical();
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}
}
}
Loading