Skip to content

Commit f77c4ad

Browse files
Integrate a function of an inverse function of a linear beside its powers under the linear (#1929)
* Integrate a function of an inverse of a linear beside its powers under the linear Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * Record the inverse functions of a linear beside its powers in BREAKING-CHANGES Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 9f18899 commit f77c4ad

4 files changed

Lines changed: 140 additions & 0 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,19 @@ back after. Each answer is in three cases by the sign of `4 a/c - (b/c)^2`
457457
| `"(a + b*x^3)^(1/3)/(x^2*(a*d - b*d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 773 characters |
458458
| `"1/(x^2*(1 - x^3)^(2/3)*(1 + x^3))".ToEntity().Integrate("x")` | `integral(...)` | 471 characters |
459459

460+
### A function of an inverse function of a linear beside powers of multiples of that linear is integrated under it
461+
462+
**Answers where there were none.** `(c k + d k x)^3 (a + b asinh(c + d x))^2` ran out of time, and so did three more
463+
of Rubi's 7.1.5 and 7.2.5. Under `u = c + d x` it is `k^3 u^3 (a + b asinh(u))^2`, which is answered, divided by `d`
464+
([#718](https://github.com/asc-community/AngouriMath/issues/718)).
465+
466+
| Input | Was (2.5.0) | Now |
467+
|---|---|---|
468+
| `"(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^2".ToEntity().Integrate("x")` | `integral(...)` | 3,574 characters |
469+
| `"(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^3".ToEntity().Integrate("x")` | `integral(...)` | 6,188 characters |
470+
| `"(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^4".ToEntity().Integrate("x")` | `integral(...)` | 9,539 characters |
471+
| `"(c*k+d*k*x)*(a+b*acosh(c+d*x))^4".ToEntity().Integrate("x")` | `integral(...)` | 3,607 characters |
472+
460473
### `a + i a tan` beside the tangent's differential is lowered over its conjugate
461474

462475
**Answers where there were none.** `sqrt(a + i a tan(x))/(c + d tan(x))^(3/2)` ran past thirty seconds:

‎Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26647,6 +26647,72 @@ static void Add(Dictionary<int, ERational> into, int k, ERational value)
2664726647
return answer.Nodes.Any(node => node == MathS.NaN) ? null : answer;
2664826648
}
2664926649

26650+
/// <summary>
26651+
/// A function of an inverse function of a linear <c>L = c + d x</c> times powers of multiples of
26652+
/// <c>L</c>, <c>(c e + d e x)^3 (a + b arsinh(c + d x))^2</c>, under <c>u = L</c>: each power of
26653+
/// <c>k L</c> is <c>(k u)^m</c>, the inverse function's argument is <c>u</c>, and the integral is
26654+
/// the one in <c>u</c> over <c>d</c>.
26655+
/// </summary>
26656+
/// <remarks>
26657+
/// <c>x^3 (a + b arsinh(x))^2</c> is answered in half a second, and the rules timed out on
26658+
/// Rubi's 7.1.5 <c>(c e + d e x)^3 (a + b arsinh(c + d x))^2</c>, which is that in <c>u</c>.
26659+
/// https://github.com/asc-community/AngouriMath/issues/718
26660+
/// </remarks>
26661+
internal static Entity? SolveAFunctionOfAnInverseOfALinearBesideItsPowersUnderTheLinear(Entity expr, Entity.Variable x)
26662+
{
26663+
if (!Integration.AnsweringTheQuestionAsked)
26664+
return null;
26665+
// The linear: the argument of an inverse function, with a constant term, as in `arsinh(c + d x)`,
26666+
// which arrives as `ln(c + d x + sqrt((c + d x)^2 + 1))`.
26667+
Entity? linear = null;
26668+
foreach (var node in expr.Nodes)
26669+
{
26670+
Entity? argument = node switch
26671+
{
26672+
Arcsinf(var y) => y, Arccosf(var y) => y, Arctanf(var y) => y,
26673+
_ => null
26674+
};
26675+
// The logarithm's argument without its root: `c + d x` of `ln(c + d x + sqrt((c + d x)^2 + 1))`.
26676+
if (argument is null && node is Logf(var b0, var of) && b0 == MathS.e && of is Sumf)
26677+
{
26678+
var terms = Sumf.LinearChildren(of).ToList();
26679+
var roots = terms.Where(term => term is Powf(_, Number.Rational { ERational.Denominator: var den }) && den.Equals(EInteger.FromInt32(2))).ToList();
26680+
if (roots.Count == 1)
26681+
argument = terms.Where(term => term != roots[0]).Aggregate((Entity)Number.Integer.Zero, (sum, term) => sum == Number.Integer.Zero ? term : sum + term);
26682+
}
26683+
if (argument is null || !argument.ContainsNode(x))
26684+
continue;
26685+
if (!TreeAnalyzer.TryGetPolyLinear(argument, x, out var slope0, out var intercept0)
26686+
|| Functions.PartialFractions.IsZeroAsAValue(slope0) || Functions.PartialFractions.IsZeroAsAValue(intercept0))
26687+
continue;
26688+
linear = argument;
26689+
break;
26690+
}
26691+
if (linear is null)
26692+
return null;
26693+
if (!TreeAnalyzer.TryGetPolyLinear(linear, x, out var slope, out var intercept) || slope is null || intercept is null)
26694+
return null;
26695+
var u = Variable.CreateUnique(expr, "u_lin");
26696+
// Every node that is a constant multiple of L becomes that multiple of u.
26697+
var inU = expr.Replace(node =>
26698+
{
26699+
if (node == linear)
26700+
return u;
26701+
if (node is not (Sumf or Minusf) || !node.ContainsNode(x)
26702+
|| !TreeAnalyzer.TryGetPolyLinear(node, x, out var s1, out var c1) || s1 is null || c1 is null
26703+
|| Functions.PartialFractions.IsZeroAsAValue(s1))
26704+
return node;
26705+
var k = (s1 / slope).InnerSimplified;
26706+
return Functions.PartialFractions.IsZeroAsAValue((c1 - k * intercept).InnerSimplified) ? k * u : node;
26707+
});
26708+
if (inU.ContainsNode(x))
26709+
return null;
26710+
if (Integration.ComputeAsAQuestionOfItsOwn(inU.InnerSimplified, u, integrateByParts: true) is not { } integrated)
26711+
return null;
26712+
var answer = (integrated.Substitute(u, linear) / slope).InnerSimplified;
26713+
return answer.Nodes.Any(node => node == MathS.NaN) ? null : answer;
26714+
}
26715+
2665026716
/// <summary>
2665126717
/// A rational function of a sine, or of a cosine, over a quadratic in it with a symbol
2665226718
/// among the coefficients: <c>sin(x)/(a + b sin(x) + c sin(x)^2)</c>, and the same with

‎Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,9 @@ private static Entity WithItsPiecewiseSumsCombined(Entity expr)
680680
// A power of a sine, cosine or hyperbolic one over a binomial in a power of it, over the
681681
// binomial's roots, before the rules that spent the budget on `sinh(y)^4/(a + b sinh(y)^3)`.
682682
if ((answer = IndefiniteIntegralSolver.SolveAPowerOverABinomialInAPowerOfASineOverItsRoots(expr, x)) is { }) return answer;
683+
// A function of an inverse function of c + d x beside powers of multiples of it, under
684+
// u = c + d x, before the rules that timed out on `(c e + d e x)^3 (a + b arsinh(c + d x))^2`.
685+
if ((answer = IndefiniteIntegralSolver.SolveAFunctionOfAnInverseOfALinearBesideItsPowersUnderTheLinear(expr, x)) is { }) return answer;
683686
// A power of x times an inverse tangent and the logarithm of its quadratic, by parts with the
684687
// two remainders that have no antiderivative apiece paired, before the rules that timed out.
685688
if ((answer = IndefiniteIntegralSolver.SolveAPowerOfXTimesAnArctangentAndTheLogarithmOfItsQuadratic(expr, x)) is { }) return answer;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// Copyright (c) 2019-2026 Angouri.
3+
// AngouriMath is licensed under MIT.
4+
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
5+
// Website: https://am.angouri.org.
6+
//
7+
8+
using System;
9+
using AngouriMath.Extensions;
10+
using Xunit;
11+
12+
namespace AngouriMath.Tests.Calculus
13+
{
14+
/// <summary>
15+
/// A function of an inverse function of <c>c + d x</c> beside powers of multiples of it, under
16+
/// <c>u = c + d x</c>: Rubi's 7.1.5 <c>(c e + d e x)^3 (a + b arsinh(c + d x))^2</c> and 7.2.5
17+
/// <c>(c e + d e x)(a + b arcosh(c + d x))^4</c>, which timed out.
18+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
19+
/// </summary>
20+
[Trait("Area", "Calculus")]
21+
public sealed class AnInverseOfALinearBesideItsPowersIntegralTest
22+
{
23+
private static void DifferentiatesBack(string integrand, params (string, double)[] pins)
24+
{
25+
var integral = integrand.ToEntity().Integrate("x");
26+
Assert.DoesNotContain("integral(", integral.Stringize());
27+
28+
var pinned = integral.Substitute("C", 0);
29+
Entity original = integrand.ToEntity();
30+
foreach (var (name, value) in pins)
31+
{
32+
pinned = pinned.Substitute(name, value);
33+
original = original.Substitute(name, value);
34+
}
35+
var derivative = pinned.Differentiate("x");
36+
foreach (var at in new[] { -2.3, -0.7, 0.4, 1.9 })
37+
{
38+
var got = derivative.Substitute("x", at).EvalNumerical();
39+
var want = original.Substitute("x", at).EvalNumerical();
40+
var difference = Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart);
41+
var scale = Math.Max(1.0, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
42+
Assert.True(difference / scale < 1e-8,
43+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
44+
}
45+
}
46+
47+
// c + d x above 1 at every sampled x, where the inverse hyperbolic cosine is real.
48+
[Theory]
49+
[InlineData("(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^2")]
50+
[InlineData("(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^4")]
51+
[InlineData("(c*k+d*k*x)*(a+b*acosh(c+d*x))^4")]
52+
public void IsAnsweredAndDifferentiatesBack(string integrand)
53+
{
54+
DifferentiatesBack(integrand, ("a", 1.3), ("b", 0.7), ("c", 3), ("d", 0.5), ("k", 1.5));
55+
DifferentiatesBack(integrand, ("a", -0.5), ("b", 2), ("c", 4), ("d", -0.6), ("k", -0.7));
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)