@@ -32357,6 +32357,134 @@ Piecewise piecewise when piecewise.Cases.Any() => piecewise.Cases.First().Expres
3235732357 return (alpha / (p0 * slope) * product).InnerSimplified;
3235832358 }
3235932359
32360+ /// <summary>
32361+ /// <c>x^m (d + e x^2)^p (a + b F(c x))</c>, <c>F</c> an inverse trigonometric function and
32362+ /// <c>m + 2p + 3 = 0</c>, by parts against the antiderivative of <c>x^m (d + e x^2)^p</c> that is
32363+ /// one term, <c>v = x^(m + 1) (d + e x^2)^(p + 1)/(d (m + 1))</c>:
32364+ /// <c>integral = v (a + b F(c x)) - b integral v F(c x)'</c>, and <c>F(c x)'</c> is algebraic.
32365+ /// </summary>
32366+ /// <remarks>
32367+ /// <para>
32368+ /// <c>v' = x^m (d + e x^2)^p ((m + 1)(d + e x^2) + 2 (p + 1) e x^2)/(d (m + 1))</c>, and the bracket
32369+ /// is <c>(m + 1) d + (m + 2p + 3) e x^2</c>, which is <c>(m + 1) d</c> for every <c>e</c>: an
32370+ /// identity of rational functions, so the parts are exact wherever the integrand is defined, on
32371+ /// any branch of <c>F</c>. It is Rubi's choice of <c>v</c>, and the one that vanishes at
32372+ /// <c>x = 0</c>.
32373+ /// </para>
32374+ /// <para>
32375+ /// The integrator's own antiderivative of <c>x^3/(d + e x^2)^3</c> is a piecewise on <c>e = 0</c>,
32376+ /// and by parts against it spent the budget on every arm: Rubi's 5.1.4, 5.3.4, 5.5.1 and 5.6.1
32377+ /// <c>x^3 (a + b F(c x))/(d + e x^2)^3</c>, for <c>F</c> the inverse sine, tangent, secant and
32378+ /// cosecant, ran out of time, where the remainder against this <c>v</c> is answered in under a
32379+ /// second.
32380+ /// </para>
32381+ /// <para>
32382+ /// Narrow on purpose. <c>p</c> whole and at most <c>-3</c>, so that <c>v</c> is rational and
32383+ /// <c>m = -2p - 3</c> at least 3: <c>m = 1</c>, <c>x/(d + e x^2)^2</c>, is answered by parts as it
32384+ /// was, and a half-odd <c>p</c> is answered as it was beside the inverse sine and tangent and is
32385+ /// elliptic beside the secant. And not for <c>e = +-c^2 d</c>, the quadratic a multiple of
32386+ /// <c>F</c>'s own radicand, which the substitution under <c>F</c> answers.
32387+ /// https://github.com/asc-community/AngouriMath/issues/233
32388+ /// </para>
32389+ /// </remarks>
32390+ internal static Entity? SolveAPowerOfXOverAPowerOfAQuadraticTimesAnInverseTrigonometricFunctionByParts(Entity expr, Entity.Variable x, bool integrateByParts)
32391+ {
32392+ if (!Integration.AnsweringTheQuestionAsked || integratingAPowerOverAQuadraticBesideAnInverse)
32393+ return null;
32394+ // The one inverse trigonometric function, of c x.
32395+ Entity? function = null;
32396+ foreach (var node in expr.Nodes)
32397+ if ((node is Arcsinf or Arccosf or Arctanf or Arccotanf or Arcsecantf or Arccosecantf) && node.ContainsNode(x))
32398+ {
32399+ if (function is not null && function != node)
32400+ return null;
32401+ function = node;
32402+ }
32403+ var argument = function switch
32404+ {
32405+ Arcsinf(var u) => u, Arccosf(var u) => u, Arctanf(var u) => u,
32406+ Arccotanf(var u) => u, Arcsecantf(var u) => u, Arccosecantf(var u) => u,
32407+ _ => null
32408+ };
32409+ if (function is null || argument is null || !TreeAnalyzer.TryGetPolyLinear(argument, x, out var rate, out var offset)
32410+ || rate.ContainsNode(x) || !Functions.PartialFractions.IsZeroAsAValue(offset) || Functions.PartialFractions.IsZeroAsAValue(rate))
32411+ return null;
32412+ // Above the bar one factor linear in it, a + b F, and the rest; below, nothing with it.
32413+ var (numerator, denominator) = Functions.SingleQuotient.Of(expr);
32414+ if (denominator.ContainsNode(function))
32415+ return null;
32416+ Entity? linear = null;
32417+ Entity rest = Number.Integer.One;
32418+ foreach (var factor in Mulf.LinearChildren(numerator))
32419+ {
32420+ if (!factor.ContainsNode(function))
32421+ rest *= factor;
32422+ else if (linear is null)
32423+ linear = factor;
32424+ else
32425+ return null;
32426+ }
32427+ var t = Variable.CreateUnique(expr, "t_inv");
32428+ if (linear is null || !TreeAnalyzer.TryGetPolyLinear(linear.Substitute(function, t), t, out var slope, out var intercept)
32429+ || slope.ContainsNode(x) || intercept.ContainsNode(x) || Functions.PartialFractions.IsZeroAsAValue(slope))
32430+ return null;
32431+ // The rest over the denominator as K x^m Q^p, Q = d + e x^2.
32432+ Entity constant = Number.Integer.One;
32433+ Entity? quadratic = null;
32434+ var m = 0;
32435+ var p = 0;
32436+ foreach (var (side, sign) in new[] { (rest, 1), (denominator, -1) })
32437+ foreach (var factor in Mulf.LinearChildren(side))
32438+ {
32439+ if (!factor.ContainsNode(x))
32440+ {
32441+ constant = sign > 0 ? constant * factor : constant / factor;
32442+ continue;
32443+ }
32444+ var (@base, power) = factor is Powf(var b0, Number.Integer { EInteger: var e0 }) && e0.CanFitInInt32()
32445+ ? (b0, e0.ToInt32Unchecked()) : (factor, 1);
32446+ if (@base == x)
32447+ m += sign * power;
32448+ else if (quadratic is null || quadratic == @base)
32449+ {
32450+ quadratic = @base;
32451+ p += sign * power;
32452+ }
32453+ else
32454+ return null;
32455+ }
32456+ if (quadratic is null || p > -3 || m != -2 * p - 3
32457+ || !TreeAnalyzer.TryGetPolynomial(quadratic, x, out var read)
32458+ || read.Keys.Any(key => !key.IsZero && !key.Equals(EInteger.FromInt32(2)))
32459+ || !read.TryGetValue(EInteger.Zero, out var d) || !read.TryGetValue(EInteger.FromInt32(2), out var e)
32460+ || d.ContainsNode(x) || e.ContainsNode(x)
32461+ || Functions.PartialFractions.IsZeroAsAValue(d) || Functions.PartialFractions.IsZeroAsAValue(e)
32462+ || Functions.PartialFractions.IsZeroAsAValue((e - rate * rate * d).Expand())
32463+ || Functions.PartialFractions.IsZeroAsAValue((e + rate * rate * d).Expand()))
32464+ return null;
32465+ var v = constant * MathS.Pow(x, Number.Integer.Create(m + 1)) * MathS.Pow(quadratic, Number.Integer.Create(p + 1))
32466+ / (d * (m + 1));
32467+ // The remainder holds no inverse function, so it is not this integrand again; the flag is for
32468+ // whatever its own search writes.
32469+ var remainder = (slope * v * function.Differentiate(x)).InnerSimplified;
32470+ Entity? integral;
32471+ integratingAPowerOverAQuadraticBesideAnInverse = true;
32472+ try
32473+ {
32474+ integral = Integration.ComputeAsAQuestionOfItsOwn(remainder, x, integrateByParts);
32475+ }
32476+ finally
32477+ {
32478+ integratingAPowerOverAQuadraticBesideAnInverse = false;
32479+ }
32480+ if (integral is null)
32481+ return null;
32482+ var answer = v * linear - integral;
32483+ return Functions.PartialFractions.DerivativeDiffersWhereReal(answer, expr, x) ? null : answer;
32484+ }
32485+
32486+ [System.ThreadStatic] private static bool integratingAPowerOverAQuadraticBesideAnInverse;
32487+
3236032488 /// <summary>
3236132489 /// <c>x^m (a + b atan(c x))^p</c> over a power of <c>d (1 +- i c x)</c>, under <c>x = tan(u)/c</c>, where
3236232490 /// <c>1 + i tan(u)</c> is <c>e^(i u)/cos(u)</c>: the integrand in <c>u</c> is
0 commit comments