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 @@ -457,6 +457,19 @@ back after. Each answer is in three cases by the sign of `4 a/c - (b/c)^2`
| `"(a + b*x^3)^(1/3)/(x^2*(a*d - b*d*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 773 characters |
| `"1/(x^2*(1 - x^3)^(2/3)*(1 + x^3))".ToEntity().Integrate("x")` | `integral(...)` | 471 characters |

### A function of an inverse function of a linear beside powers of multiples of that linear is integrated under it

**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
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`
([#718](https://github.com/asc-community/AngouriMath/issues/718)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^2".ToEntity().Integrate("x")` | `integral(...)` | 3,574 characters |
| `"(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^3".ToEntity().Integrate("x")` | `integral(...)` | 6,188 characters |
| `"(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^4".ToEntity().Integrate("x")` | `integral(...)` | 9,539 characters |
| `"(c*k+d*k*x)*(a+b*acosh(c+d*x))^4".ToEntity().Integrate("x")` | `integral(...)` | 3,607 characters |

### `a + i a tan` beside the tangent's differential is lowered over its conjugate

**Answers where there were none.** `sqrt(a + i a tan(x))/(c + d tan(x))^(3/2)` ran past thirty seconds:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26647,6 +26647,72 @@ static void Add(Dictionary<int, ERational> into, int k, ERational value)
return answer.Nodes.Any(node => node == MathS.NaN) ? null : answer;
}

/// <summary>
/// A function of an inverse function of a linear <c>L = c + d x</c> times powers of multiples of
/// <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
/// <c>k L</c> is <c>(k u)^m</c>, the inverse function's argument is <c>u</c>, and the integral is
/// the one in <c>u</c> over <c>d</c>.
/// </summary>
/// <remarks>
/// <c>x^3 (a + b arsinh(x))^2</c> is answered in half a second, and the rules timed out on
/// 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>.
/// https://github.com/asc-community/AngouriMath/issues/718
/// </remarks>
internal static Entity? SolveAFunctionOfAnInverseOfALinearBesideItsPowersUnderTheLinear(Entity expr, Entity.Variable x)
{
if (!Integration.AnsweringTheQuestionAsked)
return null;
// The linear: the argument of an inverse function, with a constant term, as in `arsinh(c + d x)`,
// which arrives as `ln(c + d x + sqrt((c + d x)^2 + 1))`.
Entity? linear = null;
foreach (var node in expr.Nodes)
{
Entity? argument = node switch
{
Arcsinf(var y) => y, Arccosf(var y) => y, Arctanf(var y) => y,
_ => null
};
// The logarithm's argument without its root: `c + d x` of `ln(c + d x + sqrt((c + d x)^2 + 1))`.
if (argument is null && node is Logf(var b0, var of) && b0 == MathS.e && of is Sumf)
{
var terms = Sumf.LinearChildren(of).ToList();
var roots = terms.Where(term => term is Powf(_, Number.Rational { ERational.Denominator: var den }) && den.Equals(EInteger.FromInt32(2))).ToList();
if (roots.Count == 1)
argument = terms.Where(term => term != roots[0]).Aggregate((Entity)Number.Integer.Zero, (sum, term) => sum == Number.Integer.Zero ? term : sum + term);
}
if (argument is null || !argument.ContainsNode(x))
continue;
if (!TreeAnalyzer.TryGetPolyLinear(argument, x, out var slope0, out var intercept0)
|| Functions.PartialFractions.IsZeroAsAValue(slope0) || Functions.PartialFractions.IsZeroAsAValue(intercept0))
continue;
linear = argument;
break;
}
if (linear is null)
return null;
if (!TreeAnalyzer.TryGetPolyLinear(linear, x, out var slope, out var intercept) || slope is null || intercept is null)
return null;
var u = Variable.CreateUnique(expr, "u_lin");
// Every node that is a constant multiple of L becomes that multiple of u.
var inU = expr.Replace(node =>
{
if (node == linear)
return u;
if (node is not (Sumf or Minusf) || !node.ContainsNode(x)
|| !TreeAnalyzer.TryGetPolyLinear(node, x, out var s1, out var c1) || s1 is null || c1 is null
|| Functions.PartialFractions.IsZeroAsAValue(s1))
return node;
var k = (s1 / slope).InnerSimplified;
return Functions.PartialFractions.IsZeroAsAValue((c1 - k * intercept).InnerSimplified) ? k * u : node;
});
if (inU.ContainsNode(x))
return null;
if (Integration.ComputeAsAQuestionOfItsOwn(inU.InnerSimplified, u, integrateByParts: true) is not { } integrated)
return null;
var answer = (integrated.Substitute(u, linear) / slope).InnerSimplified;
return answer.Nodes.Any(node => node == MathS.NaN) ? null : answer;
}

/// <summary>
/// A rational function of a sine, or of a cosine, over a quadratic in it with a symbol
/// among the coefficients: <c>sin(x)/(a + b sin(x) + c sin(x)^2)</c>, and the same with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,9 @@ private static Entity WithItsPiecewiseSumsCombined(Entity expr)
// A power of a sine, cosine or hyperbolic one over a binomial in a power of it, over the
// binomial's roots, before the rules that spent the budget on `sinh(y)^4/(a + b sinh(y)^3)`.
if ((answer = IndefiniteIntegralSolver.SolveAPowerOverABinomialInAPowerOfASineOverItsRoots(expr, x)) is { }) return answer;
// A function of an inverse function of c + d x beside powers of multiples of it, under
// u = c + d x, before the rules that timed out on `(c e + d e x)^3 (a + b arsinh(c + d x))^2`.
if ((answer = IndefiniteIntegralSolver.SolveAFunctionOfAnInverseOfALinearBesideItsPowersUnderTheLinear(expr, x)) is { }) return answer;
// A power of x times an inverse tangent and the logarithm of its quadratic, by parts with the
// two remainders that have no antiderivative apiece paired, before the rules that timed out.
if ((answer = IndefiniteIntegralSolver.SolveAPowerOfXTimesAnArctangentAndTheLogarithmOfItsQuadratic(expr, x)) is { }) return answer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// 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 function of an inverse function of <c>c + d x</c> beside powers of multiples of it, under
/// <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
/// <c>(c e + d e x)(a + b arcosh(c + d x))^4</c>, which timed out.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AnInverseOfALinearBesideItsPowersIntegralTest
{
private static void DifferentiatesBack(string integrand, params (string, double)[] pins)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());

var pinned = integral.Substitute("C", 0);
Entity original = integrand.ToEntity();
foreach (var (name, value) in pins)
{
pinned = pinned.Substitute(name, value);
original = original.Substitute(name, value);
}
var derivative = pinned.Differentiate("x");
foreach (var at in new[] { -2.3, -0.7, 0.4, 1.9 })
{
var got = derivative.Substitute("x", at).EvalNumerical();
var want = original.Substitute("x", at).EvalNumerical();
var difference = Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart);
var scale = Math.Max(1.0, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
Assert.True(difference / scale < 1e-8,
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
}

// c + d x above 1 at every sampled x, where the inverse hyperbolic cosine is real.
[Theory]
[InlineData("(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^2")]
[InlineData("(c*k+d*k*x)^3*(a+b*asinh(c+d*x))^4")]
[InlineData("(c*k+d*k*x)*(a+b*acosh(c+d*x))^4")]
public void IsAnsweredAndDifferentiatesBack(string integrand)
{
DifferentiatesBack(integrand, ("a", 1.3), ("b", 0.7), ("c", 3), ("d", 0.5), ("k", 1.5));
DifferentiatesBack(integrand, ("a", -0.5), ("b", 2), ("c", 4), ("d", -0.6), ("k", -0.7));
}
}
}
Loading