Skip to content

Commit 364eda3

Browse files
Split a symbolic power of a product beside a symbolic power of one of its factors (#1887)
* Split a symbolic power of a product beside a symbolic power of a factor (P Q)^r is K P^r Q^r with K constant between the zeros of P and Q for any exponent free of x, not only a rational one: K is exp(2 pi i n r) for a whole n. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * Record the answers a symbolic power of a product split gives 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 1763843 commit 364eda3

3 files changed

Lines changed: 85 additions & 3 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,21 @@ The answers are as large as the split integrands' answers, which are piecewise i
733733
| `"(a - b*x^2)^(3/2)/sqrt(a^2 - b^2*x^4)".ToEntity().Integrate("x")` | `integral(...)` | 6,543 characters |
734734
| `"1/((a - b*x^2)^(1/2)*sqrt(a^2 - b^2*x^4))".ToEntity().Integrate("x")` | `integral(...)` | 877 characters |
735735

736+
### A symbolic power of a product beside a symbolic power of one of its factors is split
737+
738+
**Answers where there were none.** `(d + k x)^(-3 - 2p) (a d k + (c d^2 + a k^2) x + c d k x^2)^p` was declined:
739+
the split of a power of a product beside a power of a factor took rational exponents only. `(P Q)^r` is
740+
`K P^r Q^r` with `K` constant between the zeros of `P` and `Q` for any exponent free of x, so a symbolic one is
741+
split too, and the powers of `P` gather ([#718](https://github.com/asc-community/AngouriMath/issues/718)).
742+
743+
| Input | Was (2.5.0) | Now |
744+
|---|---|---|
745+
| `"(d + k*x)^(-3 - 2*p)*(a*d*k + (c*d^2 + a*k^2)*x + c*d*k*x^2)^p".ToEntity().Integrate("x")` | not done in 60 seconds | 349 characters |
746+
| `"(d + k*x)^m/(a*d*k + (c*d^2 + a*k^2)*x + c*d*k*x^2)^m".ToEntity().Integrate("x")` | `integral(...)` | 215 characters |
747+
| `"(A + B*x)*(a*c + b*c*x)^m/(a^2 + 2*a*b*x + b^2*x^2)^(3/2)".ToEntity().Integrate("x")` | `integral(...)` | 476 characters |
748+
| `"(d + k*x)^m*(f + g*x)^3/(a*d*k + (c*d^2 + a*k^2)*x + c*d*k*x^2)^m".ToEntity().Integrate("x")` | `integral(...)` | 1,817 characters |
749+
| `"(1 - x^4)^n/(1 + x + x^2 + x^3)^n".ToEntity().Integrate("x")` | `integral(...)` | 147 characters |
750+
736751
### A secant or a cosecant beside a power of a sum of them is read as a power of the cosine or the sine
737752

738753
**Answers where there were none.** `sec(x) sqrt(sec(x) + tan(x))` was declined, with the rest of Rubi's 4.7.7

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19334,7 +19334,8 @@ Entity TakeOut(Entity node)
1933419334
}
1933519335

1933619336
/// <summary>
19337-
/// A root of a product beside a root of one of its factors, the product split:
19337+
/// A root of a product beside a root of one of its factors, or a symbolic power of one
19338+
/// beside a symbolic power of a factor, the product split:
1933819339
/// <c>(P Q)^r</c> is <c>K P^r Q^r</c>, where <c>K = (P Q)^r/(P^r Q^r)</c> is constant wherever
1933919340
/// it is defined, for the same reason as in
1934019341
/// <see cref="SolveByTakingTheWholePowersOutOfAPowerOfAProduct"/>. The powers of <c>P</c>
@@ -19350,7 +19351,7 @@ Entity TakeOut(Entity node)
1935019351
{
1935119352
if (!Integration.AnsweringTheQuestionAsked || splittingARootOfAProduct)
1935219353
return null;
19353-
var roots = new List<(Entity Node, Entity Base, Number.Rational Exponent)>();
19354+
var roots = new List<(Entity Node, Entity Base, Entity Exponent)>();
1935419355
Gather(expr);
1935519356
if (roots.Count < 2)
1935619357
return null;
@@ -19393,7 +19394,12 @@ void Gather(Entity node)
1939319394
Gather(above);
1939419395
Gather(below);
1939519396
break;
19396-
case Powf(var @base, Number.Rational exponent) when exponent is not Number.Integer && @base.ContainsNode(x):
19397+
// A symbolic exponent as well: K is exp(2 pi i n r) for a whole n constant
19398+
// between the zeros of P and Q, whatever r is. Rubi's 1.2.1.2:2389,
19399+
// `(d + e x)^(-3 - 2 p) ((d + e x) (a e + c d x))^p`, gathers into
19400+
// `(d + e x)^(-3 - p) (a e + c d x)^p`.
19401+
case Powf(var @base, var exponent) when exponent is not Number.Integer && !exponent.ContainsNode(x) && @base.ContainsNode(x)
19402+
&& (exponent is Number.Rational || exponent.Vars.Any()):
1939719403
roots.Add((node, @base, exponent));
1939819404
break;
1939919405
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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 symbolic power of a product of two linears beside a symbolic power of one of them:
16+
/// <c>(P Q)^p</c> is a constant times <c>P^p Q^p</c>, and the powers of <c>P</c> gather.
17+
/// Rubi's 1.2.1.2 <c>(d + e x)^(-3 - 2 p) (a d e + (c d^2 + a e^2) x + c d e x^2)^p</c>, written
18+
/// here with <c>k</c> for <c>e</c>, which is Euler's number.
19+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
20+
/// </summary>
21+
[Trait("Area", "Calculus")]
22+
public sealed class ASymbolicPowerOfAProductBesideAPowerOfAFactorIntegralTest
23+
{
24+
private static void DifferentiatesBack(string integrand, params (string, double)[] pins)
25+
{
26+
var integral = integrand.ToEntity().Integrate("x");
27+
Assert.DoesNotContain("integral(", integral.Stringize());
28+
29+
// Pinned before it is differentiated, with exponents whose denominators are even, so
30+
// that every power of a negative base is read on the principal branch
31+
// (https://github.com/asc-community/AngouriMath/issues/204).
32+
var pinned = integral.Substitute("C", 0);
33+
Entity original = integrand.ToEntity();
34+
foreach (var (name, value) in pins)
35+
{
36+
pinned = pinned.Substitute(name, value);
37+
original = original.Substitute(name, value);
38+
}
39+
var derivative = pinned.Differentiate("x");
40+
foreach (var at in new[] { -2.3, -0.7, 0.4, 1.9 })
41+
{
42+
var got = derivative.Substitute("x", at).EvalNumerical();
43+
var want = original.Substitute("x", at).EvalNumerical();
44+
var difference = Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart);
45+
var scale = Math.Max(1.0, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
46+
Assert.True(difference / scale < 1e-8,
47+
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
48+
}
49+
}
50+
51+
[Theory]
52+
[InlineData("(d+k*x)^(-3-2*p)*(a*d*k+(c*d^2+a*k^2)*x+c*d*k*x^2)^p")]
53+
[InlineData("(d+k*x)^(-5-2*p)*(a*d*k+(c*d^2+a*k^2)*x+c*d*k*x^2)^p")]
54+
[InlineData("(a*d*k+(c*d^2+a*k^2)*x+c*d*k*x^2)^p/(d+k*x)^p")]
55+
public void IsAnsweredAndDifferentiatesBack(string integrand)
56+
{
57+
DifferentiatesBack(integrand, ("a", 2), ("c", 1.5), ("d", 1.25), ("k", 2), ("p", 0.25));
58+
DifferentiatesBack(integrand, ("a", -1), ("c", 2), ("d", -0.5), ("k", 1.5), ("p", -1.75));
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)