Skip to content

Commit 5813051

Browse files
let method=:general2 be valid
1 parent 7474027 commit 5813051

File tree

3 files changed

+46
-27
lines changed

3 files changed

+46
-27
lines changed

src/gauss.jl

+19-17
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ function _₂F₁(a, b, c, z; method::Symbol = :general, kwds...)
5050
end
5151
if method == :positive
5252
return _₂F₁positive(a, b, c, z; kwds...)
53+
elseif method == :general2
54+
return _₂F₁general2(a, b, c, z; kwds...)
5355
else#if method == :general
5456
return _₂F₁general(a, b, c, z; kwds...) # catch-all
5557
end
@@ -103,55 +105,55 @@ This polyalgorithm is designed based on the review
103105
104106
> J. W. Pearson, S. Olver and M. A. Porter, [Numerical methods for the computation of the confluent and Gauss hypergeometric functions](https://doi.org/10.1007/s11075-016-0173-0), *Numer. Algor.*, **74**:821–866, 2017.
105107
"""
106-
function _₂F₁general2(a, b, c, z)
108+
function _₂F₁general2(a, b, c, z; kwds...)
107109
T = promote_type(typeof(a), typeof(b), typeof(c), typeof(z))
108110
if z == 1
109-
return _₂F₁argument_unity(a, b, c, z)
111+
return _₂F₁argument_unity(a, b, c, z; kwds...)
110112
elseif real(b) < real(a)
111-
return _₂F₁general2(b, a, c, z)
113+
return _₂F₁general2(b, a, c, z; kwds...)
112114
elseif abs(z) ρ || -a ℕ₀ || -b ℕ₀
113-
return _₂F₁maclaurin(a, b, c, z)
115+
return _₂F₁maclaurin(a, b, c, z; kwds...)
114116
elseif !isalmostwellpoised(a, b, c)
115-
return exp((c-a-b)*log1p(-z))*_₂F₁general2(c-a, c-b, c, z)
117+
return exp((c-a-b)*log1p(-z))*_₂F₁general2(c-a, c-b, c, z; kwds...)
116118
elseif abs(z / (z - 1)) ρ && absarg(1 - z) < convert(real(T), π) # 15.8.1
117119
w = z/(z-1)
118-
return _₂F₁maclaurin(a, c-b, c, w)*exp(-a*log1p(-z))
120+
return _₂F₁maclaurin(a, c-b, c, w; kwds...)*exp(-a*log1p(-z))
119121
elseif abs(inv(z)) ρ && absarg(-z) < convert(real(T), π)
120122
w = inv(z)
121123
if isapprox(a, b) # 15.8.8
122-
return gamma(c)/gamma(a)/gamma(c-a)*(-w)^a*_₂F₁logsumalt(a, c-a, z, w)
124+
return gamma(c)/gamma(a)/gamma(c-a)*(-w)^a*_₂F₁logsumalt(a, c-a, z, w; kwds...)
123125
elseif a-b # 15.8.2
124-
return gamma(c)*((-w)^a*gamma(b-a)/gamma(b)/gamma(c-a)*_₂F₁maclaurin(a, a-c+1, a-b+1, w)+(-w)^b*gamma(a-b)/gamma(a)/gamma(c-b)*_₂F₁maclaurin(b, b-c+1, b-a+1, w))
126+
return gamma(c)*((-w)^a*gamma(b-a)/gamma(b)/gamma(c-a)*_₂F₁maclaurin(a, a-c+1, a-b+1, w; kwds...)+(-w)^b*gamma(a-b)/gamma(a)/gamma(c-b)*_₂F₁maclaurin(b, b-c+1, b-a+1, w; kwds...))
125127
end # TODO: full 15.8.8
126128
elseif abs(inv(1-z)) ρ && absarg(-z) < convert(real(T), π)
127129
w = inv(1-z)
128130
if isapprox(a, b) # 15.8.9
129-
return gamma(c)*exp(-a*log1p(-z))/gamma(a)/gamma(c-b)*_₂F₁logsum(a, c-a, z, w, 1)
131+
return gamma(c)*exp(-a*log1p(-z))/gamma(a)/gamma(c-b)*_₂F₁logsum(a, c-a, z, w, 1; kwds...)
130132
elseif a-b # 15.8.3
131-
return gamma(c)*(exp(-a*log1p(-z))*gamma(b-a)/gamma(b)/gamma(c-a)*_₂F₁maclaurin(a, c-b, a-b+1, w)+exp(-b*log1p(-z))*gamma(a-b)/gamma(a)/gamma(c-b)*_₂F₁maclaurin(b, c-a, b-a+1, w))
133+
return gamma(c)*(exp(-a*log1p(-z))*gamma(b-a)/gamma(b)/gamma(c-a)*_₂F₁maclaurin(a, c-b, a-b+1, w; kwds...)+exp(-b*log1p(-z))*gamma(a-b)/gamma(a)/gamma(c-b)*_₂F₁maclaurin(b, c-a, b-a+1, w; kwds...))
132134
end # TODO: full 15.8.9
133135
elseif abs(1-z) ρ && absarg(z) < convert(real(T), π) && absarg(1-z) < convert(real(T), π)
134136
w = 1-z
135137
if isapprox(c, a + b) # 15.8.10
136-
return gamma(c)/gamma(a)/gamma(b)*_₂F₁logsum(a, b, z, w, -1)
138+
return gamma(c)/gamma(a)/gamma(b)*_₂F₁logsum(a, b, z, w, -1; kwds...)
137139
elseif c - a - b # 15.8.4
138-
return gamma(c)*(gamma(c-a-b)/gamma(c-a)/gamma(c-b)*_₂F₁maclaurin(a, b, a+b-c+1, w)+exp((c-a-b)*log1p(-z))*gamma(a+b-c)/gamma(a)/gamma(b)*_₂F₁maclaurin(c-a, c-b, c-a-b+1, w))
140+
return gamma(c)*(gamma(c-a-b)/gamma(c-a)/gamma(c-b)*_₂F₁maclaurin(a, b, a+b-c+1, w; kwds...)+exp((c-a-b)*log1p(-z))*gamma(a+b-c)/gamma(a)/gamma(b)*_₂F₁maclaurin(c-a, c-b, c-a-b+1, w; kwds...))
139141
end # TODO: full 15.8.10
140142
elseif abs(1-inv(z)) ρ && absarg(z) < convert(real(T), π) && absarg(1-z) < convert(real(T), π)
141143
w = 1-inv(z)
142144
if isapprox(c, a + b) # 15.8.11
143-
return gamma(c)*z^(-a)/gamma(a)*_₂F₁logsumalt(a, b, z, w)
145+
return gamma(c)*z^(-a)/gamma(a)*_₂F₁logsumalt(a, b, z, w; kwds...)
144146
elseif c - a - b # 15.8.5
145-
return gamma(c)*(z^(-a)*gamma(c-a-b)/gamma(c-a)/gamma(c-b)*_₂F₁maclaurin(a, a-c+1, a+b-c+1, w)+z^(a-c)*(1-z)^(c-a-b)*gamma(a+b-c)/gamma(a)/gamma(b)*_₂F₁maclaurin(c-a, 1-a, c-a-b+1, w))
147+
return gamma(c)*(z^(-a)*gamma(c-a-b)/gamma(c-a)/gamma(c-b)*_₂F₁maclaurin(a, a-c+1, a+b-c+1, w; kwds...)+z^(a-c)*(1-z)^(c-a-b)*gamma(a+b-c)/gamma(a)/gamma(b)*_₂F₁maclaurin(c-a, 1-a, c-a-b+1, w; kwds...))
146148
end # TODO: full 15.8.11
147149
elseif abs(z-0.5) > 0.5
148150
if isapprox(a, b) && !isapprox(c, a+0.5)
149-
return gamma(c)/gamma(a)/gamma(c-a)*(0.5-z)^(-a)*_₂F₁continuationalt(a, c, 0.5, z)
151+
return gamma(c)/gamma(a)/gamma(c-a)*(0.5-z)^(-a)*_₂F₁continuationalt(a, c, 0.5, z; kwds...)
150152
elseif a-b
151-
return gamma(c)*(gamma(b-a)/gamma(b)/gamma(c-a)*(0.5-z)^(-a)*_₂F₁continuation(a, a+b, c, 0.5, z) + gamma(a-b)/gamma(a)/gamma(c-b)*(0.5-z)^(-b)*_₂F₁continuation(b, a+b, c, 0.5, z))
153+
return gamma(c)*(gamma(b-a)/gamma(b)/gamma(c-a)*(0.5-z)^(-a)*_₂F₁continuation(a, a+b, c, 0.5, z; kwds...) + gamma(a-b)/gamma(a)/gamma(c-b)*(0.5-z)^(-b)*_₂F₁continuation(b, a+b, c, 0.5, z; kwds...))
152154
end
153155
end
154-
return pFqweniger((a, b), (c, ), z)
156+
return pFqweniger((a, b), (c, ), z; kwds...) # _₂F₁taylor(a, b, c, z; kwds...)
155157
end
156158

157159
# Special case of (-x)^a*_₂F₁ to handle LogNumber correctly in RiemannHilbert.jl

src/specialfunctions.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ function _₂F₁continuationalt(a::Number, c::Number, z₀::Number, z::Number)
471471
izz₀ = inv(z-z₀)
472472
e0, e1 = one(T), (a+one(T))*(one(T)-2z₀)+(2a+one(T))*z₀-c
473473
f0, f1 = zero(T), one(T)-2z₀
474-
cⱼ = log(z₀-z)+2digamma(one(T))-digamma(a)-digamma(c-a)
474+
cⱼ = log(z₀-z)+2digamma(one(real(T)))-digamma(a)-digamma(c-a)
475475
S₀ = cⱼ
476476
cⱼ += 2/one(T)-one(T)/a
477477
C = a*izz₀
@@ -489,7 +489,7 @@ end
489489

490490
function _₂F₁logsum(a::Number, b::Number, z::Number, w::Number, s::Int)
491491
T = promote_type(typeof(a), typeof(b), typeof(z), typeof(w))
492-
cⱼ = 2digamma(one(T))-digamma(a)-digamma(b)+s*log1p(-z)
492+
cⱼ = 2digamma(one(real(T)))-digamma(a)-digamma(b)+s*log1p(-z)
493493
C, S, j = one(T), cⱼ, 0
494494
while abs(C) > 8abs(S)*eps(real(T)) || j 1
495495
C *= (a+j)/(j+1)^2*(b+j)*w
@@ -502,7 +502,7 @@ end
502502

503503
function _₂F₁logsumalt(a::Number, b::Number, z::Number, w::Number)
504504
T = promote_type(typeof(a), typeof(b), typeof(z), typeof(w))
505-
d, cⱼ = one(T)-b, 2digamma(one(T))-digamma(a)-digamma(b)-log(-w)
505+
d, cⱼ = one(T)-b, 2digamma(one(real(T)))-digamma(a)-digamma(b)-log(-w)
506506
C, S, j = one(T), cⱼ, 0
507507
while abs(C) > 8abs(S)*eps(real(T)) || j 1
508508
C *= (a+j)/(j+1)^2*(d+j)*w

test/runtests.jl

+24-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using HypergeometricFunctions, SpecialFunctions, Test
22
import LinearAlgebra: norm
33
import HypergeometricFunctions: iswellpoised, isalmostwellpoised, M, U,
4-
pochhammer,
5-
_₂F₁general, pFqdrummond, pFqweniger, pFq2string
4+
pochhammer, _₂F₁general, _₂F₁general2,
5+
pFqdrummond, pFqweniger, pFq2string
66

77
const rtol = 1.0e-3
88
const NumberType = Float64
@@ -24,9 +24,9 @@ const NumberType = Float64
2424
end
2525

2626
@testset "Hypergeometric Functions" begin
27-
@testset "_₂F₁ vs _₂F₁general" begin
27+
@testset "_₂F₁ vs _₂F₁general vs _₂F₁general2" begin
2828
e = exp(1.0)
29-
regression_max_accumulated_error = 8.0e-13 # discovered by running the test
29+
regression_max_accumulated_error = 2^12*eps() # discovered by running the test
3030
for z in (.9rand(Float64, 10), 10rand(ComplexF64, 10))
3131
j = 1
3232
for (a,b,c) in ((2/e, 1.3, 1.3), (1.2, 3, 1.2), (-0.4, 0.4, 0.5),
@@ -46,10 +46,27 @@ end
4646
@test error_accum < regression_max_accumulated_error
4747
j += 1
4848
end
49+
for (a,b,c) in ((2/e, 1.3, 1.3), (1.2, 3, 1.2), (-0.4, 0.4, 0.5),
50+
(-0.3, 1.3, 0.5), (0.35, 0.85, 0.5), (0.5, 1.0, 1.5),
51+
(0.3, 0.7, 1.5), (0.7, 1.3, 1.5), (0.35, 0.85, 1.5),
52+
(3.0, 1.0, 2.0), (-2.0, 1.0, 2.0), (-3.0, 1.0, 2.0),
53+
(1.0, -4.0, 2.0), (1.0, 1.5, 2.5))
54+
error_accum = 0.0
55+
for zi in z
56+
twoFone = _₂F₁(a,b,c,zi)
57+
aa,bb,cc = big(a),big(b),big(c)
58+
twoFonegeneral2 = convert(Complex{Float64},_₂F₁general2(aa, bb, cc, big(zi)))
59+
norm(twoFone / twoFonegeneral2 - 1) > sqrt(eps()) && println("This is ₂F₁($a,$b;$c;zi) - ₂F₁general2($a,$b;$c;zi): ", norm(twoFone / twoFonegeneral2 - 1), " ", twoFone, " ", twoFonegeneral2, " ", isfinite(twoFone), " ", isfinite(twoFonegeneral2), " this is zi: ", zi)
60+
error_accum += Float64(norm(twoFone / twoFonegeneral2 - 1))
61+
end
62+
@test error_accum < regression_max_accumulated_error
63+
j += 1
64+
end
4965
end
50-
@testset "Test that _₂F₁ is inferred for Float32 arguments" begin
51-
@test @inferred(_₂F₁(0.3f0, 0.7f0, 1.3f0, 0.1f0)) Float32(_₂F₁(0.3, 0.7, 1.3, 0.1))
52-
end
66+
end
67+
68+
@testset "Test that _₂F₁ is inferred for Float32 arguments" begin
69+
@test @inferred(_₂F₁(0.3f0, 0.7f0, 1.3f0, 0.1f0)) Float32(_₂F₁(0.3, 0.7, 1.3, 0.1))
5370
end
5471

5572
@testset "method = positive" begin

0 commit comments

Comments
 (0)