Skip to content

Commit ba77f7a

Browse files
A sum of two squares below the bar, beside a repeated factor, is split over its conjugates (#1804)
Under u = tan(x) and t = sqrt(c + d u), the 1 + u^2 of (c + d tan(x))^(3/2)/(a + b tan(x))^2 is (t^2 - c)^2 + d^2, a quartic beside the square of a d + b (t^2 - c). The split by residues reads factors of the first and second degree only, so the quotient went to the Hermite reduction, which solved for its numerators with the symbols in every entry and ran past two minutes. A written sum of two squares P^2 + Q^2, the greater of their degrees two, beside a repeated factor, is written (P - i Q)(P + i Q) now and the quotient asked again: four rows of 4.3.2.1 with one root over a power of a + b tan are answered in one to two seconds, and two with two roots, where the sum is (b - d t^2)^2 + (c t^2 - a)^2 under the root of their quotient. The constants in that split hold i, and it is short only with them in lowest terms (#1788's first part). Part of #718. Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 54c1d10 commit ba77f7a

3 files changed

Lines changed: 123 additions & 0 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,24 @@ rules' already
302302
| `"asin(sqrt(1 + x) - sqrt(x))".ToEntity().Integrate("x")` | `integral(...)` | an antiderivative in `arcsin(sqrt(1 + x) - sqrt(x))` |
303303
| `"x^3*atan(-sqrt(x)+sqrt(1+x))".ToEntity().Integrate("x")` | `integral(...)` | an antiderivative in the arctangent |
304304

305+
### A sum of two squares below the bar, beside a repeated factor, is split over its conjugates
306+
307+
**Answers where there were none.** `(c + d tan(x))^(3/2)/(a + b tan(x))^2` was declined in 2.5.0 and ran
308+
past two minutes since. Under `u = tan(x)` and `t = sqrt(c + d u)` the `1 + u^2` the tangent leaves is
309+
`(t^2 - c)^2 + d^2`, a quartic beside the square of `a d + b (t^2 - c)`, and the Hermite reduction
310+
solved for the numerators over it with the symbols in every entry. A written sum of two squares
311+
`P^2 + Q^2`, the greater of their degrees two, beside a repeated factor, is `(P - i Q)(P + i Q)` below
312+
the bar now, and over those every factor is one the split by residues reads -- under a root of the
313+
quotient of two such linears the sum is `(b - d t^2)^2 + (c t^2 - a)^2`. Rubi's 4.3.2.1
314+
([#718](https://github.com/asc-community/AngouriMath/issues/718)).
315+
316+
| Input | Was (2.5.0) | Now |
317+
|---|---|---|
318+
| `"(c + d*tan(x))^(3/2)/(a + b*tan(x))^2".ToEntity().Integrate("x")` | `integral(...)`; past two minutes on the unreleased master | arctangents and logarithms of `sqrt(c + d tan(x))`, in two seconds |
319+
| `"(c + d*tan(x))^(5/2)/(a + b*tan(x))^2".ToEntity().Integrate("x")` | `integral(...)` | the same |
320+
| `"(c + d*tan(x))^(3/2)/(a + b*tan(x))^3".ToEntity().Integrate("x")` | `integral(...)` | the same |
321+
| `"1/((a + b*tan(x))^(3/2)*(c + d*tan(x))^(3/2))".ToEntity().Integrate("x")` | `integral(...)`; past a minute on the unreleased master | in the root of the quotient of the two, in a second |
322+
305323
### A function of `x^n` for a symbolic `n` beside a power of `x` is integrated in a power of `x`
306324

307325
**Answers where there were none.** `x^(-1 + 4n)/(a + b x^n + c x^(2n))` and the rest of Rubi's

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,19 @@ is var (multiple, leftover)
851851
?? Integration.ComputeIndefiniteIntegral(inY, y, integrateByParts)) is { } inTheShiftedVariable)
852852
return inTheShiftedVariable.Substitute(y, (x + shift).InnerSimplified);
853853

854+
// A written factor that is a sum of two squares, `P^2 + Q^2` with the greater of their
855+
// degrees two, beside a repeated factor: it is `(P - i Q)(P + i Q)`, and over those two
856+
// the split by residues above reads every factor. `1 + u^2` beside a root of a
857+
// linear is `(t^2 - c)^2 + d^2` under `t = sqrt(c + d u)`, a quartic nothing splits, and
858+
// the Hermite reduction below solved for its numerators with the symbols in every entry:
859+
// `(c + d tan(x))^(3/2)/(a + b tan(x))^2` ran past two minutes. Once: what this writes
860+
// has no such factor left.
861+
if (Mulf.LinearChildren(denominator).Any(f => f.ContainsNode(x) && f is Powf(_, Number.Integer { EInteger.Sign: > 0 } e) && e != Number.Integer.One)
862+
&& OverTheConjugatesOfASumOfTwoSquares(denominator, x) is { } overTheConjugates
863+
&& (SolveByPartialFractions(numerator / overTheConjugates, x, integrateByParts)
864+
?? Integration.ComputeIndefiniteIntegral(numerator / overTheConjugates, x, integrateByParts)) is { } overConjugates)
865+
return overConjugates;
866+
854867
// A denominator with a written repeated factor takes the Hermite reduction first:
855868
// the rational part of the answer in one linear solve, and what is left is a proper
856869
// fraction over a squarefree denominator for the splits below. `(1 + x^2)/(x (1 + x^3)^2)`
@@ -14451,6 +14464,43 @@ private static bool IsASumOfMonomials(Entity expr, Entity.Variable x)
1445114464
return changed ? product : null;
1445214465
}
1445314466

14467+
/// <summary>
14468+
/// <paramref name="denominator"/> with every written factor <c>P^2 + Q^2</c>, <c>P</c> and
14469+
/// <c>Q</c> polynomials in <paramref name="x"/> the greater of whose degrees is two, written
14470+
/// as <c>(P - i Q)(P + i Q)</c>, with its power; <see langword="null"/> where there is none,
14471+
/// or where nothing in the quotient is a symbol: with numbers alone the split over the reals
14472+
/// reads a biquadratic as it is. Not of the first degree: <c>(a + b x)^2 + k^2</c> is a
14473+
/// quadratic every rule reads, by an arctangent.
14474+
/// </summary>
14475+
private static Entity? OverTheConjugatesOfASumOfTwoSquares(Entity denominator, Entity.Variable x)
14476+
{
14477+
static int? DegreeOfAPolynomial(Entity expr, Entity.Variable x)
14478+
=> !expr.ContainsNode(x) ? 0
14479+
: TreeAnalyzer.TryGetPolynomial(expr, x, out var read) && read.Count > 0 && read.Values.All(coefficient => !coefficient.ContainsNode(x))
14480+
&& read.Keys.All(power => power.Sign >= 0 && power.CanFitInInt32())
14481+
? read.Keys.Max()!.ToInt32Unchecked() : null;
14482+
if (!denominator.Vars.Any(symbol => symbol != x))
14483+
return null;
14484+
var changed = false;
14485+
Entity product = Number.Integer.One;
14486+
foreach (var factor in Mulf.LinearChildren(denominator))
14487+
{
14488+
var (@base, power) = factor is Powf(var b, Number.Integer { EInteger.Sign: > 0 } p) ? (b, p) : (factor, Number.Integer.One);
14489+
if (@base is Sumf(Powf(var first, Number.Integer(2)), Powf(var second, Number.Integer(2)))
14490+
&& (first.ContainsNode(x) || second.ContainsNode(x))
14491+
&& DegreeOfAPolynomial(first, x) is { } firstDegree && DegreeOfAPolynomial(second, x) is { } secondDegree
14492+
&& System.Math.Max(firstDegree, secondDegree) == 2)
14493+
{
14494+
var (minus, plus) = (first - MathS.i * second, first + MathS.i * second);
14495+
product *= power == Number.Integer.One ? minus * plus : MathS.Pow(minus, power) * MathS.Pow(plus, power);
14496+
changed = true;
14497+
continue;
14498+
}
14499+
product *= factor;
14500+
}
14501+
return changed ? product : null;
14502+
}
14503+
1445414504
/// <summary>
1445514505
/// <paramref name="denominator"/> with every quadratic factor that has a root off the real line
1445614506
/// in common with a linear factor beside it written as its leading coefficient times the
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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 sum of two squares below the bar beside a repeated factor, written over its two
16+
/// conjugates. Under <c>u = tan(x)</c> and <c>t = sqrt(c + d u)</c>, the <c>1 + u^2</c> of
17+
/// Rubi's 4.3.2.1 <c>(c + d tan(x))^(3/2)/(a + b tan(x))^2</c> is <c>(t^2 - c)^2 + d^2</c>,
18+
/// a quartic beside the square of <c>a d + b (t^2 - c)</c>; the Hermite reduction solved for
19+
/// its numerators with the symbols in every entry and ran past two minutes. Written as
20+
/// <c>(t^2 - c - i d)(t^2 - c + i d)</c>, every factor is one the split by residues reads.
21+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
22+
/// </summary>
23+
/// <remarks>
24+
/// Under a root of the quotient of two such linears the sum is <c>(b - d t^2)^2 + (c t^2 - a)^2</c>,
25+
/// both parts in <c>t</c>, and its conjugates are quadratics as well. The integrands are real
26+
/// where <c>a + b tan(x)</c> and <c>c + d tan(x)</c> are positive, which the points are.
27+
/// </remarks>
28+
[Trait("Area", "Calculus")]
29+
public sealed class SumOfTwoSquaresBelowTheBarIntegralTest
30+
{
31+
[Theory]
32+
[InlineData("(c + d*tan(x))^(3/2)/(a + b*tan(x))^2")]
33+
[InlineData("(c + d*tan(x))^(5/2)/(a + b*tan(x))^2")]
34+
[InlineData("(c + d*tan(x))^(3/2)/(a + b*tan(x))^3")]
35+
[InlineData("x^4/((a*d + (x^2 - c)*b)^2*((x^2 - c)^2 + d^2))")]
36+
[InlineData("1/((a + b*tan(x))^(3/2)*(c + d*tan(x))^(3/2))")]
37+
[InlineData("1/((a + b*tan(x))^(5/2)*(c + d*tan(x))^(3/2))")]
38+
public void OverItsConjugates(string integrand)
39+
{
40+
var integral = integrand.ToEntity().Integrate("x");
41+
Assert.DoesNotContain("integral(", integral.Stringize());
42+
Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7).Substitute("c", 1.1).Substitute("d", 0.6);
43+
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
44+
var original = Pinned(integrand.ToEntity());
45+
foreach (var at in new[] { 0.2, 0.5, 0.9, 1.2 })
46+
{
47+
var want = original.Substitute("x", at).EvalNumerical();
48+
var got = derivative.Substitute("x", at).EvalNumerical();
49+
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
50+
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart)),
51+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
52+
}
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)