Skip to content

Commit 954a9cd

Browse files
Read the root's quadratic at a symbolic pole without the slope's condition (#1888)
* Read the root's quadratic at a symbolic pole without the slope's condition Q(p) for p = -n/m comes back with `provided not m = 0` where Q has no linear term, and the table read no quadratic in t through the condition: `1/((d + k x) sqrt(a + c x^2))` was declined where `1/((d + x) sqrt(a + c x^2))` was not. The slope is not zero for a linear, so the value is read bare. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * Decline a pole off the real line beside a root, where the sign of x - p is written With the slope's condition gone, the rule for a linear beside a root read `1 + i a x` as a pole at i/a, and wrote sgn(x - i/a) with nothing checking it after; `1/(e^(3 i atan(a x)) x^3)` lost its answer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * Record the answers a pole with a symbolic slope beside a root 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 364eda3 commit 954a9cd

4 files changed

Lines changed: 94 additions & 5 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,24 @@ the first power: for a higher power the secant's own rules answer
466466
| `"cos(c + d*x)^2*(A + B*sec(c + d*x) + C*sec(c + d*x)^2)/(a + b*sec(c + d*x))".ToEntity().Integrate("x")` | `integral(...)` | 12,065 characters |
467467
| `"sin(x)^2/(a + b*csc(x))".ToEntity().Integrate("x")` | `integral(...)` | 898 characters |
468468

469+
### A linear with a symbolic slope beside a root of a quadratic with no linear term is integrated
470+
471+
**Answers where there were none.** `sqrt(a + c x^2)/(x (d + k x))` was declined where `sqrt(a + b x + c x^2)/(x (d + k x))`
472+
was answered. The rule for a constant over a linear beside the root works at the linear's root `p = -d/k`. Without
473+
a linear term, the quadratic's value there came back with `provided not k = 0` attached, and the table read no
474+
quadratic through that condition. The value is read without the condition now: a linear's slope is not zero. A
475+
linear with the imaginary unit in it is still declined there, as it was by accident before
476+
([#718](https://github.com/asc-community/AngouriMath/issues/718)).
477+
478+
| Input | Was (2.5.0) | Now |
479+
|---|---|---|
480+
| `"sqrt(a + c*x^2)/(x*(d + k*x))".ToEntity().Integrate("x")` | `integral(...)` | 1,362 characters |
481+
| `"sqrt(a + c*x^2)/(x^3*(d + k*x))".ToEntity().Integrate("x")` | `integral(...)` | 1,710 characters |
482+
| `"1/(x*(d + k*x)*sqrt(a + c*x^2))".ToEntity().Integrate("x")` | `integral(...)` | 1,067 characters |
483+
| `"1/(x*(d + k*x)*(a + c*x^2)^(3/2))".ToEntity().Integrate("x")` | `integral(...)` | 1,769 characters |
484+
| `"1/(x^3*(d + k*x)^2*sqrt(a + c*x^2))".ToEntity().Integrate("x")` | `integral(...)` | 2,801 characters |
485+
| `"sqrt(a + c/x^2)/(d + k*x)".ToEntity().Integrate("x")` | `integral(...)` | 1,373 characters |
486+
469487
### One linear twice is not two linear powers
470488

471489
**Answers that had no value.** `(a c + b c x)^(-3 - 2 p) (f + g x) (a^2 + 2 a b x + b^2 x^2)^p` was answered

‎Sources/AngouriMath/Functions/Algebra/Polynomials/PartialFractions.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ private static Entity ExpandedOverTheSymbols(Entity expr)
696696
}
697697

698698
/// <summary>Whether a number off the real line is among the nodes of <paramref name="expr"/>.</summary>
699-
private static bool HoldsTheImaginaryUnit(Entity expr)
699+
internal static bool HoldsTheImaginaryUnit(Entity expr)
700700
=> expr.Nodes.Any(node => node is Complex number && number is not Real && !number.ImaginaryPart.IsZero);
701701

702702
/// <summary>

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18095,12 +18095,20 @@ Dictionary<EInteger, Entity> PowerOfQ(int j)
1809518095
foreach (var coefficient in new[] { a, b, c, m, n, numerator, constant })
1809618096
if (coefficient.Evaled is Number.Complex and not Number.Real)
1809718097
return null;
18098+
// And a pole off the real line is not one: the answer is written with the sign of
18099+
// x - p, and nothing checks it after. `1 + i a x` beside a root, what
18100+
// `e^(3 i atan(a x))` is written as, has its pole at `i/a`.
18101+
if (Functions.PartialFractions.HoldsTheImaginaryUnit(m) || Functions.PartialFractions.HoldsTheImaginaryUnit(n))
18102+
return null;
1809818103

1809918104
// (x - p) with p = -n/m, and K = numerator/(m constant).
1810018105
var p = (-n / m).InnerSimplified;
1810118106
var k = (numerator / (m * constant)).InnerSimplified;
18102-
var atP = (a * p * p + b * p + c).InnerSimplified;
18103-
var slopeAtP = (2 * a * p + b).InnerSimplified;
18107+
// Bare: `3 (-d/k)^2 + 2` comes back `... provided not k = 0`, the linear's own slope
18108+
// not vanishing, and the table read no quadratic in t through the condition --
18109+
// `1/((d + k x) sqrt(2 + 3 x^2))` was declined where `1/((d + x) sqrt(2 + 3 x^2))` was not.
18110+
var atP = Functions.PartialFractions.Bare((a * p * p + b * p + c).InnerSimplified);
18111+
var slopeAtP = Functions.PartialFractions.Bare((2 * a * p + b).InnerSimplified);
1810418112
var t = Variable.CreateUnique(expr, "t_recip");
1810518113
var inT = 1 / MathS.Pow(atP * MathS.Sqr(t) + slopeAtP * t + a, Number.Rational.Create(1, 2));
1810618114
if (IntegralPatterns.TryStandardIntegrals(inT, t) is not { } g)
@@ -18489,12 +18497,13 @@ static Entity WithoutConditions(Entity coefficient)
1848918497
if (coefficient.Evaled is Number.Complex and not Number.Real)
1849018498
return null;
1849118499
var p = (-n / m).InnerSimplified;
18492-
var atP = (a * p * p + b * p + c).InnerSimplified;
18500+
// Bare, as in the rule for a single linear: the slope's condition is not a case.
18501+
var atP = Functions.PartialFractions.Bare((a * p * p + b * p + c).InnerSimplified);
1849318502
// A root of the radicand leaves a linear under the root, which is not this.
1849418503
if (VanishesIdentically(atP)
1849518504
|| Functions.PartialFractions.TaylorCoefficientsAtTheRoot(numerator, p, power, x) is not { } taylor)
1849618505
return null;
18497-
var slopeAtP = (2 * a * p + b).InnerSimplified;
18506+
var slopeAtP = Functions.PartialFractions.Bare((2 * a * p + b).InnerSimplified);
1849818507
var t = Variable.CreateUnique(expr, "t_recip");
1849918508
// P(p + 1/t) t^(k - 1) is the sum of the Taylor coefficients times t^(k - 1 - j), and
1850018509
// (x - p)^k is L^k/m^k.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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 constant over a linear with a symbolic slope beside the root of a quadratic with no
16+
/// linear term: the quadratic's value at the pole came back with the slope's condition on it,
17+
/// and the table read no quadratic through it. Rubi's 1.2.1.4
18+
/// <c>sqrt(a + c x^2)/(x (d + e x))</c>, written here with <c>k</c> for <c>e</c>, which is
19+
/// Euler's number.
20+
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
21+
/// </summary>
22+
[Trait("Area", "Calculus")]
23+
public sealed class APoleWithASymbolicSlopeBesideARootIntegralTest
24+
{
25+
private static void DifferentiatesBack(string integrand, params (string, double)[] pins)
26+
{
27+
var integral = integrand.ToEntity().Integrate("x");
28+
Assert.DoesNotContain("integral(", integral.Stringize());
29+
30+
// Pinned before it is differentiated: the answer carries `sgn(x + d/k)`, whose
31+
// derivative is read where its argument is a number.
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("1/((d+k*x)*sqrt(2+3*x^2))")]
53+
[InlineData("sqrt(a+c*x^2)/(x*(d+k*x))")]
54+
[InlineData("1/(x^2*(d+k*x)*sqrt(a+c*x^2))")]
55+
[InlineData("1/(x*(d+k*x)^2*sqrt(a+c*x^2))")]
56+
public void IsAnsweredAndDifferentiatesBack(string integrand)
57+
{
58+
DifferentiatesBack(integrand, ("a", 2), ("c", 1.5), ("d", 1.25), ("k", 2));
59+
DifferentiatesBack(integrand, ("a", -1), ("c", 2), ("d", -0.5), ("k", 1.5));
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)