Skip to content

Commit 55bd4f2

Browse files
add a positive method to 2F1
- attempt at 2F1 argument unity - reformat tests
1 parent 274185d commit 55bd4f2

File tree

6 files changed

+356
-298
lines changed

6 files changed

+356
-298
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "HypergeometricFunctions"
22
uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a"
3-
version = "0.3.9"
3+
version = "0.3.10"
44

55
[deps]
66
DualNumbers = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74"

src/HypergeometricFunctions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module HypergeometricFunctions
77

88
using DualNumbers, LinearAlgebra, SpecialFunctions
99

10-
export _₁F₁, _₂F₁, _₃F₂, pFq, positive₂F₁
10+
export _₁F₁, _₂F₁, _₃F₂, pFq
1111

1212
include("specialfunctions.jl")
1313
include("gauss.jl")

src/gauss.jl

Lines changed: 67 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"""
44
Compute the Gauss hypergeometric function `₂F₁(a, b; c; z)`.
55
"""
6-
function _₂F₁(a, b, c, z)
6+
function _₂F₁(a, b, c, z; method::Symbol = :general)
77
if real(b) < real(a)
8-
return _₂F₁(b, a, c, z) # ensure a ≤ b
8+
return _₂F₁(b, a, c, z; method = method) # ensure a ≤ b
99
elseif isequal(a, c) # 1. 15.4.6
1010
return exp(-b*log1p(-z))
1111
elseif isequal(b, c) # 1. 15.4.6
@@ -47,29 +47,23 @@ function _₂F₁(a, b, c, z)
4747
elseif isequal(c, 2.5) && abeqcd(a, b, 1, 1.5)
4848
return speciallog(z)
4949
end
50-
return _₂F₁general(a, b, c, z) # catch-all
51-
end
52-
53-
# Special case of (-x)^a*_₂F₁ to handle LogNumber correctly in RiemannHilbert.jl
54-
function mxa_₂F₁(a, b, c, z)
55-
if isequal(c, 2)
56-
if abeqcd(a, b, 1) # 6. 15.4.1
57-
return log1p(-z)
58-
end
59-
elseif isequal(c, 4)
60-
if abeqcd(a, b, 2)
61-
return 6*(-2 + (1-2/z)*log1p(-z))
62-
end
50+
if method == :positive
51+
return _₂F₁positive(a, b, c, z)
52+
else#if method == :general
53+
return _₂F₁general(a, b, c, z) # catch-all
6354
end
64-
return (-z)^a*_₂F₁(a, b, c, z)
6555
end
6656

6757
"""
68-
Compute the Gauss hypergeometric function `₂F₁(a, b; c; z)` with positive parameters a, b, and c and non-negative argument z. Useful for statisticians.
58+
Compute the Gauss hypergeometric function `₂F₁(a, b; c; z)` with positive parameters a, b, and c and argument 0 ≤ z ≤ 1. Useful for statisticians.
6959
"""
70-
function positive₂F₁(a, b, c, z)
60+
function _₂F₁positive(a, b, c, z)
7161
@assert a > 0 && b > 0 && c > 0 && 0 z 1
72-
return _₂F₁maclaurin(a, b, c, z)
62+
if z == 1
63+
return _₂F₁argument_unity(a, b, c, float(z))
64+
else
65+
return _₂F₁maclaurin(a, b, c, z)
66+
end
7367
end
7468

7569
"""
@@ -79,12 +73,13 @@ This polyalgorithm is designed based on the paper
7973
N. Michel and M. V. Stoitsov, Fast computation of the Gauss hypergeometric function with all its parameters complex with application to the Pöschl–Teller–Ginocchio potential wave functions, Comp. Phys. Commun., 178:535–551, 2008.
8074
"""
8175
function _₂F₁general(a, b, c, z)
82-
T = promote_type(typeof(a), typeof(b), typeof(c), typeof(z))
83-
84-
real(b) < real(a) && return _₂F₁general(b, a, c, z)
85-
real(c) < real(a) + real(b) && return exp((c-a-b)*log1p(-z))*_₂F₁general(c-a, c-b, c, z)
86-
87-
if abs(z) ρ || -a ℕ₀ || -b ℕ₀
76+
if z == 1
77+
return _₂F₁argument_unity(a, b, c, float(z))
78+
elseif real(b) < real(a)
79+
return _₂F₁general(b, a, c, z)
80+
elseif !isalmostwellpoised(a, b, c)
81+
return exp((c-a-b)*log1p(-z))*_₂F₁general(c-a, c-b, c, z)
82+
elseif abs(z) ρ || -a ℕ₀ || -b ℕ₀
8883
return _₂F₁maclaurin(a, b, c, z)
8984
elseif abs(z/(z-1)) ρ
9085
return exp(-a*log1p(-z))_₂F₁maclaurin(a, c-b, c, z/(z-1))
@@ -109,7 +104,13 @@ J. W. Pearson, S. Olver and M. A. Porter, Numerical methos for the computation o
109104
"""
110105
function _₂F₁general2(a, b, c, z)
111106
T = promote_type(typeof(a), typeof(b), typeof(c), typeof(z))
112-
if abs(z) ρ || -a ℕ₀ || -b ℕ₀
107+
if z == 1
108+
return _₂F₁argument_unity(a, b, c, float(z))
109+
elseif real(b) < real(a)
110+
return _₂F₁general(b, a, c, z)
111+
elseif !isalmostwellpoised(a, b, c)
112+
return exp((c-a-b)*log1p(-z))*_₂F₁general2(c-a, c-b, c, z)
113+
elseif abs(z) ρ || -a ℕ₀ || -b ℕ₀
113114
return _₂F₁maclaurin(a, b, c, z)
114115
elseif abs(z / (z - 1)) ρ && absarg(1 - z) < convert(real(T), π) # 15.8.1
115116
w = z/(z-1)
@@ -151,3 +152,43 @@ function _₂F₁general2(a, b, c, z)
151152
end
152153
return pFqweniger([a, b], [c], z)
153154
end
155+
156+
# Special case of (-x)^a*_₂F₁ to handle LogNumber correctly in RiemannHilbert.jl
157+
function mxa_₂F₁(a, b, c, z)
158+
if isequal(c, 2)
159+
if abeqcd(a, b, 1) # 6. 15.4.1
160+
return log1p(-z)
161+
end
162+
elseif isequal(c, 4)
163+
if abeqcd(a, b, 2)
164+
return 6*(-2 + (1-2/z)*log1p(-z))
165+
end
166+
end
167+
return (-z)^a*_₂F₁(a, b, c, z)
168+
end
169+
170+
function _₂F₁argument_unity(a, b, c, z)
171+
T = promote_type(typeof(a), typeof(b), typeof(c), typeof(z))
172+
a, b, c = T(a), T(b), T(c)
173+
if iswellpoised(a, b, c)
174+
return exp(loggamma(c)-loggamma(c-a)+loggamma(c-a-b)-loggamma(c-b))
175+
elseif isalmostwellpoised(a, b, c)
176+
if a + b == c
177+
f = loggamma(c)-loggamma(a)-loggamma(b)
178+
if isreal(f)
179+
return T(Inf)
180+
else
181+
return T(Inf)*sign(exp(f))
182+
end
183+
else
184+
return T(NaN)
185+
end
186+
else # !isalmostwellpoised(a, b, c)
187+
f = loggamma(c)-loggamma(a)+gamma(a+b-c)-loggamma(b)
188+
if isreal(f)
189+
return T(Inf)
190+
else
191+
return T(Inf)*sign(exp(f))
192+
end
193+
end
194+
end

src/generalized.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ function pFq(α::AbstractVector, β::AbstractVector, z; kwds...)
1111
elseif length(α) == 1 && length(β) == 0
1212
return exp(-α[1]*log1p(-z))
1313
elseif length(α) == 1 && length(β) == 1
14-
return _₁F₁(α[1], β[1], float(z))
14+
return _₁F₁(α[1], β[1], float(z); kwds...)
1515
elseif length(α) == 2 && length(β) == 1
16-
return _₂F₁(α[1], α[2], β[1], float(z))
16+
return _₂F₁(α[1], α[2], β[1], float(z); kwds...)
1717
elseif length(α) length(β)
1818
if real(z) 0
1919
return pFqmaclaurin(α, β, float(z); kwds...)

src/specialfunctions.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ Base.in(n::Dual, ::Type{ℤ}) = dualpart(n) == 0 && realpart(n) ∈ ℤ
8080
abeqcd(a, b, cd) = isequal(a, b) && isequal(b, cd)
8181
abeqcd(a, b, c, d) = isequal(a, c) && isequal(b, d)
8282

83+
iswellpoised(a, b, c) = real(c - a - b) > 0
84+
isalmostwellpoised(a, b, c) = real(c - a - b) 0
85+
8386
absarg(z) = abs(angle(z))
8487

8588
sqrtatanhsqrt(x) = x == 0 ? one(x) : (s = sqrt(-x); atan(s)/s)

0 commit comments

Comments
 (0)