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 @@ -561,6 +561,22 @@ power, which by parts answers as before ([#233](https://github.com/asc-community
| `"x*(a+b*atanh(c*x))^2/(d+c*d*x)^3".ToEntity().Integrate("x")` | `integral(...)` | 731 characters |
| `"x*(a+b*acoth(c*x))^2/(d+c*d*x)^3".ToEntity().Integrate("x")` | `integral(...)` | 756 characters |

### A hyperbolic quotient over a linear in its cosine is asked as the cosine's

**Answers where there were none, and shorter than master's.** Rubi's 6.2.5 `sech(x)^3/(a + b cosh(x))` and 6.5.3
`sech(x)^4/(a + b sech(x))` ran past the corpus's budget. Under the tangent of the half argument each is a cube of
`1 + t^2` beside a symbolic quadratic, and was answered in about 118,000 characters. By Osborn's rule each is a rational
function of a cosine alone, over a sum linear in it, and that question is now asked first. In the cosine,
`1/(cos(s)^3 (a + b cos(s)))` is a partial fraction in it
([#233](https://github.com/asc-community/AngouriMath/issues/233)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"sech(x)^3/(a+b*cosh(x))".ToEntity().Integrate("x")` | `integral(...)` | 2,396 characters, where before this change master gave 118,366 |
| `"sech(x)^4/(a+b*sech(x))".ToEntity().Integrate("x")` | `integral(...)` | 2,412 characters, where before this change master gave 118,032 |
| `"cosh(x)^3/(a+b*cosh(x))".ToEntity().Integrate("x")` | `integral(...)` | 1,108 characters, where before this change master gave 2,858 |
| `"cosh(x)^2/(a+b*sech(x))".ToEntity().Integrate("x")` | `integral(...)` | 802 characters, where before this change master gave 2,820 |

### An arctangent over a power of `d (1 + i c x)` is integrated under the tangent

**Answers where there were none.** `(a + b atan(c x))^2/(d + i c d x)^2` ran out of time, and so did seven more of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ static bool APowerOfAQuotientOfLinearsVanishingAtPlusOrMinusOne(Entity inU, Vari
/// <c>s</c> took seconds to decline, five gigabytes for <c>1/(1 + sinh(x)^3)</c> against 0.2.
/// </remarks>
internal static Entity? SolveAHyperbolicIntegrandAsATrigonometricOne(Entity expr, Entity.Variable x, bool integrateByParts, bool rationalToo,
bool overAQuadraticInTheSine = false)
bool overAQuadraticInTheSine = false, bool overALinearInTheCosine = false)
{
// Only the question asked: a question in s is not cheap to decline, and below the top every
// sub-question a route gives up on would ask it.
Expand Down Expand Up @@ -1498,6 +1498,12 @@ static bool APowerOfAQuotientOfLinearsVanishingAtPlusOrMinusOne(Entity inU, Vari
&& AFactorAboveAQuadraticInS(inS, s))
return null;
var question = MathS.i / slopeOfL * inS;
// Or, asked as early, only a rational function of the cosine alone over a sum linear in it, or in
// the secant: under the tangent of the half argument Rubi's `sech(x)^3/(a + b cosh(x))` is a
// cube of `1 + t^2` beside a symbolic quadratic, answered in 118,366 characters, where in the
// cosine `1/(cos(s)^3 (a + b cos(s)))` is a partial fraction in it.
if (overALinearInTheCosine && !IsARationalFunctionOfTheCosineOverALinearInIt(inS, s))
return null;
// Or the one rule for a rational function of a sine or a cosine over a symbolic quadratic in
// it, asked ahead of the exponential substitution and cheap to decline.
if ((overAQuadraticInTheSine
Expand All @@ -1520,6 +1526,26 @@ static bool APowerOfAQuotientOfLinearsVanishingAtPlusOrMinusOne(Entity inU, Vari
}).Substitute(s, -MathS.i * linear).InnerSimplified;
return Functions.PartialFractions.DerivativeHoldsAtSampledPoints(answer, expr, x) ? answer : null;

// Whether inS holds s only in cos(s), and below the bar a sum linear in it, to the first power:
// over `b^2 + 2 a b cos(s) + a^2 cos(s)^2`, the square of one, the question in s took four times
// the memory the tangent did, Rubi's 6.7.1 `(a + b cosh(x))/(b + a cosh(x))^2`.
static bool IsARationalFunctionOfTheCosineOverALinearInIt(Entity inS, Variable s)
{
var cosine = MathS.Cos(s);
foreach (var node in inS.Nodes)
if (node.ContainsNode(s) && node != cosine && node != s
&& node is not (Sumf or Minusf or Mulf or Divf or Powf(_, Number.Integer)))
return false;
var (_, below) = Functions.SingleQuotient.Of(inS);
var y = Variable.CreateUnique(inS, "y_osb");
bool ASum(Entity node) => node is Sumf or Minusf && node.ContainsNode(cosine);
bool Linear(Entity sum) => TreeAnalyzer.TryGetPolynomial(sum.Replace(node => node == cosine ? y : node), y, out var read)
&& read.Keys.Max()!.Equals(EInteger.One);
var sums = Mulf.LinearChildren(below).Where(ASum).ToList();
return sums.Count > 0 && sums.All(Linear)
&& !Mulf.LinearChildren(below).Any(factor => factor is Powf(var @base, _) && ASum(@base));
}

// Whether inS, rational in cos(s) alone or sin(s) alone, has a denominator of degree three or
// more that t = tan(s/2) or t = tan(s) leaves with an irreducible factor of degree above two,
// which the rational rules write only as a sum over roots. The cosine, and the square of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,9 @@ internal static bool ASumOverRootsWouldAnswer
// `sinh(x)^2/(a + b sinh(x) + c sinh(x)^2)` is a quartic with symbols, and its partial
// fractions ran past the budget, where the sine's rule answers the question in s at once.
if ((answer = IndefiniteIntegralSolver.SolveAHyperbolicIntegrandAsATrigonometricOne(expr, x, integrateByParts, rationalToo: true, overAQuadraticInTheSine: true)) is { }) return answer;
// And one of the cosine alone over a sum linear in it, which the tangent made a cube of
// `1 + t^2` beside a symbolic quadratic: `sech(x)^3/(a + b cosh(x))` in 118,366 characters.
if ((answer = IndefiniteIntegralSolver.SolveAHyperbolicIntegrandAsATrigonometricOne(expr, x, integrateByParts, rationalToo: true, overALinearInTheCosine: true)) is { }) return answer;
if ((answer = IndefiniteIntegralSolver.SolveARationalFunctionOfTheHyperbolicTangent(expr, x, integrateByParts)) is { }) return answer;
// A rational function of a sine or a cosine over a quadratic in it with a symbol
// among the coefficients, split over the quadratic's two roots: under the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// 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 rational function of the hyperbolic cosine alone over a sum linear in it, or in the secant,
/// asked by Osborn's rule as one of the cosine before the tangent of the half argument: under that
/// tangent Rubi's 6.2.5 <c>sech(x)^3/(a + b cosh(x))</c> and 6.5.3 <c>sech(x)^4/(a + b sech(x))</c>
/// are a cube of <c>1 + t^2</c> beside a symbolic quadratic, and were answered in 118,366 and
/// 118,032 characters, past the corpus's budget.
/// <a href="https://github.com/asc-community/AngouriMath/issues/233">#233</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AHyperbolicQuotientOverALinearInItsCosineIntegralTest
{
[Theory]
// Rubi 6.2.5:89.
[InlineData("sech(x)^3/(a + b*cosh(x))")]
// Rubi 6.5.3:139.
[InlineData("sech(x)^4/(a + b*sech(x))")]
[InlineData("cosh(x)^2/(a + b*sech(x))")]
public void IsAnsweredInTheCosine(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
var text = integral.Stringize();
Assert.DoesNotContain("integral(", text);
Assert.True(text.Length < 5000, $"{integrand} came back in {text.Length} characters");
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
foreach (var at in new[] { -2.2, -0.9, 0.3, 1.4, 2.1 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).EvalNumerical();
Assert.False(got.IsNaN, $"d/dx of the antiderivative of {integrand} has no value at x = {at}, where the integrand is {want}");
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