diff --git a/Sources/AngouriMath/Numerics/PreciseEvaluation.cs b/Sources/AngouriMath/Numerics/PreciseEvaluation.cs index 2eb168b50..1674c0bc0 100644 --- a/Sources/AngouriMath/Numerics/PreciseEvaluation.cs +++ b/Sources/AngouriMath/Numerics/PreciseEvaluation.cs @@ -545,6 +545,34 @@ private PreciseComplexInterval EvaluateOtherThanArithmetic(Entity expr) return BySlope(Evaluate(argument), Number.Shi, z => Divide(Half(Subtract(Exp(z), Exp(Negate(z)))), z), cutEnd: null); case Chif(var argument): return BySlope(Evaluate(argument), Number.Chi, z => Divide(Half(Add(Exp(z), Exp(Negate(z)))), z), cutEnd: EDecimal.Zero); + // The upper incomplete gamma function of a constant order, through its derivative in z, + // -z^(a - 1) e^(-z), jumping across the negative real axis but at a whole order a >= 1. The + // power is the principal one, as this evaluation's powers are. An order known only to its + // last place, as 1/3 is, is taken at both ends, and the value is the hull of the two: across + // an interval that narrow the function is linear in its order. + // https://github.com/asc-community/AngouriMath/issues/2075 + case IncompleteGammaf(var parameter, var lowerLimit): + { + var order = Evaluate(parameter); + if (!order.IsFinite) + return undefined; + var z = Evaluate(lowerLimit); + var entire = order.IsReal && order.Re.Low.CompareTo(order.Re.High) == 0 && order.Re.Low.IsInteger() && order.Re.Low.Sign > 0; + PreciseComplexInterval AtTheOrder(EDecimal re, EDecimal im) + { + var a = Number.Complex.Create(re, im); + var aLessOne = new PreciseComplexInterval(PreciseInterval.Exactly(re.Subtract(EDecimal.One)), PreciseInterval.Exactly(im)); + return BySlope(z, w => Number.IncompleteGamma(a, w), w => Negate(Multiply(Pow(w, aLessOne), Exp(Negate(w)))), cutEnd: entire ? null : EDecimal.Zero); + } + var low = AtTheOrder(order.Re.Low, order.Im.Low); + if (order.Re.Low.CompareTo(order.Re.High) == 0 && order.Im.Low.CompareTo(order.Im.High) == 0 || !low.IsFinite) + return low; + var high = AtTheOrder(order.Re.High, order.Im.High); + if (!high.IsFinite) + return undefined; + return new(new(EDecimal.Min(low.Re.Low, high.Re.Low), EDecimal.Max(low.Re.High, high.Re.High)), + new(EDecimal.Min(low.Im.Low, high.Im.Low), EDecimal.Max(low.Im.High, high.Im.High))); + } // A sum over the roots of a polynomial, the form Rothstein–Trager answers in: each // root enclosed, the summand worked out on its rectangle, and the terms added. // https://github.com/asc-community/AngouriMath/issues/1285 diff --git a/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs index ef6a87725..d913ebd4d 100644 --- a/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/APowerBesideAnExponentialOfAPowerIntegralTest.cs @@ -136,6 +136,17 @@ public void APositiveRateIsTakenOutOfThePower() [InlineData("(a + b*x)^2*e^(-c*(d + f*x)^3)")] public void APolynomialBesideAFunctionOfAShiftedLinear(string integrand) => DifferentiatesBack(integrand); + /// + /// A symbolic power of an inverse hyperbolic function, which its substitution writes as powers of u beside + /// exponentials of it, each a gamma function. The route had these answers and turned them away: its check at + /// sampled points could not evaluate a gamma function, and so had no point to compare at. Rubi's 7.1.4 and 7.2.4. + /// + [Theory] + [InlineData("x*asinh(c*x)^n/sqrt(1 + c^2*x^2)")] + [InlineData("(d + f*asinh(c*x))^n*sqrt(1 + c^2*x^2)")] + [InlineData("x*(d + f*acosh(f*x))^n/(sqrt(f*x - 1)*sqrt(f*x + 1))")] + public void ASymbolicPowerOfAnInverseHyperbolicFunction(string integrand) => DifferentiatesBack(integrand); + /// /// Not where the integral is elementary, an exponential integral or an error function: those keep the form /// they had. diff --git a/Sources/Tests/UnitTests/Core/IntervalEvaluationTest.cs b/Sources/Tests/UnitTests/Core/IntervalEvaluationTest.cs index e7c27a0be..a8425030a 100644 --- a/Sources/Tests/UnitTests/Core/IntervalEvaluationTest.cs +++ b/Sources/Tests/UnitTests/Core/IntervalEvaluationTest.cs @@ -200,6 +200,10 @@ public void TheSizeOfALargeComplexValueIsFinite() [InlineData("Shi(3/2) + Chi(-1) + Chi(1 + 2i)")] [InlineData("e^(-2) * Ei(sqrt(3)) + Si(pi/4)^2")] [InlineData("iverson(pi > 3) * sqrt(2) + iverson(e < 2)")] + [InlineData("gamma(5/2, 3/2) + gamma(-3, 7/10)")] + [InlineData("gamma(1/2 + i, 2 - i)")] + [InlineData("gamma(3/2, -2) + gamma(4, -1)")] + [InlineData("gamma(1/3, 2) + gamma(2/7 + i/3, 1/2 + i)")] public void ThePreciseIntervalHoldsTheValue(string expression) { var expr = expression.ToEntity(); @@ -247,7 +251,9 @@ public void AnExactZeroFactorIsZero(string expression) /// x erf(x) differentiates to erf(x) and more -- is checked, where reading /// none of them left no point to compare at and the answer was turned away. On the real /// line left of 0 the values are the ones on the cut: Chi(-0.61) is - /// Chi(0.61) + i pi, and li(-0.61) is complex. + /// Chi(0.61) + i pi, and li(-0.61) is complex. The incomplete gamma function was + /// not read, and every answer holding one was turned away by the routes that check theirs: + /// Rubi's x arsinh(a x)^n/sqrt(1 + a^2 x^2) among them. /// [Theory] [InlineData("x * erf(x) + e^(-x^2)/sqrt(pi)", "erf(x)")] @@ -257,6 +263,8 @@ public void AnExactZeroFactorIsZero(string expression) [InlineData("x * Ei(x) - e^x", "Ei(x)")] [InlineData("x * Chi(x) - sinh(x)", "Chi(x)")] [InlineData("x * li(x) - Ei(2 * ln(x))", "li(x)")] + [InlineData("x * gamma(5/2, x) - gamma(7/2, x)", "gamma(5/2, x)")] + [InlineData("x * gamma(n, x) - gamma(n + 1, x)", "gamma(n, x)")] public void ADerivativeKeepingASpecialFunctionIsChecked(string antiderivative, string integrand) { var x = MathS.Var("x");