Skip to content

Commit

Permalink
improve generic capabilities (#26)
Browse files Browse the repository at this point in the history
* improve generic capabilities

- add complex number tests

- fix tablature

- add kmax parameter to some algorithms

- reorganize directory so that gauss.jl only has methods for 2F1

- unify the error checking

* use log1p for 1F0

Calling float(z) closes #15.
  • Loading branch information
MikaelSlevinsky authored Jul 7, 2020
1 parent 62ca7c6 commit 123e404
Show file tree
Hide file tree
Showing 10 changed files with 690 additions and 674 deletions.
1 change: 0 additions & 1 deletion .codecov.yml

This file was deleted.

13 changes: 3 additions & 10 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
name = "HypergeometricFunctions"
uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a"
version = "0.2.3"
version = "0.3"

[deps]
DualNumbers = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
DualNumbers = "0.5, 0.6"
IntervalArithmetic = "0.15, 0.16"
DualNumbers = "0.5, 0.6, 0.7"
SpecialFunctions = "0.7, 0.8, 0.9, 0.10"
julia = "1"

[extras]
IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "IntervalArithmetic"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
# HypergeometricFunctions.jl
A Julia package for calculating hypergeometric functions

This package implements some hypergeometric functions. In particular, the Gauss hypergeometric function is available as `_₂F₁(a,b,c,z)`, and also `_₃F₂([a1, a2, a3], [b1,b2], z)` and more general `mFn([a1,…,am], [b1,…,bn], z)`.
This package implements the generalized hypergeometric function `pFq([a1,…,am], [b1,…,bn], z)`. In particular, the Gauss hypergeometric function is available as `_₂F₁(a, b, c, z)`, and also `_₃F₂([a1, a2, a3], [b1, b2], z)`.
7 changes: 4 additions & 3 deletions src/HypergeometricFunctions.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
"""
This module calculates (generalized) hypergeometric functions:
mFn(a;b;z) = Σ_{k=0}^∞ (a_1,k) ⋯ (a_m,k) / (b_1,k) ⋯ (b_n,k) zᵏ/k!
pFq(α, β; z) = Σ_{k=0}^∞ (α_1)ₖ ⋯ (α_p)ₖ / (β_1)ₖ ⋯ (β_q)ₖ zᵏ/k!
"""
module HypergeometricFunctions

using DualNumbers, LinearAlgebra, SpecialFunctions

export _₂F₁, _₃F₂, mFn
export _₂F₁, _₃F₂, pFq

include("gauss.jl")
include("specialfunctions.jl")
include("gauss.jl")
include("generalized.jl")
include("drummond.jl")
include("weniger.jl")

Expand Down
83 changes: 49 additions & 34 deletions src/drummond.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# using Drummond's sequence transformation

# ₀F₀(;z)
function drummond0F0(z::T) where T
function drummond0F0(z::T; kmax::Int = 10_000) where T
if norm(z) < eps(real(T))
return one(T)
end
Expand All @@ -18,7 +18,7 @@ function drummond0F0(z::T) where T
Dhi, Dlo = ((k+2)*ζ-1)*Dhi + k*ζ*Dlo, Dhi
Thi, Tlo = Nhi/Dhi, Thi
k += 1
while abs(Thi-Tlo) > 10*abs(Thi)*eps(real(T)) && k < 10_000
while k < kmax && errcheck(Tlo, Thi, 10eps(real(T)))
Nhi, Nlo = ((k+2)*ζ-1)*Nhi + k*ζ*Nlo, Nhi
Dhi, Dlo = ((k+2)*ζ-1)*Dhi + k*ζ*Dlo, Dhi
Thi, Tlo = Nhi/Dhi, Thi
Expand All @@ -28,9 +28,9 @@ function drummond0F0(z::T) where T
end

# ₁F₀(α;z)
function drummond1F0::T1, z::T2) where {T1, T2}
function drummond1F0::T1, z::T2; kmax::Int = 10_000) where {T1, T2}
T = promote_type(T1, T2)
absα = T(abs(α))
absα = abs(T(α))
if norm(z) < eps(real(T)) || norm(α) < eps(absα)
return one(T)
end
Expand All @@ -56,7 +56,7 @@ function drummond1F0(α::T1, z::T2) where {T1, T2}
Nhi /= α+k+1
Dhi /= α+k+1
k += 1
while abs(Thi-Tlo) > 10*abs(Thi)*eps(real(T)) && k < 10_000
while k < kmax && errcheck(Tlo, Thi, 10eps(real(T)))
Nhi, Nlo = ((k+2)*ζ-+2k+1))*Nhi + k*-1)*Nlo, Nhi
Dhi, Dlo = ((k+2)*ζ-+2k+1))*Dhi + k*-1)*Dlo, Dhi
Thi, Tlo = Nhi/Dhi, Thi
Expand All @@ -71,7 +71,7 @@ function drummond1F0(α::T1, z::T2) where {T1, T2}
end

# ₀F₁(β;z)
function drummond0F1::T1, z::T2) where {T1, T2}
function drummond0F1::T1, z::T2; kmax::Int = 10_000) where {T1, T2}
T = promote_type(T1, T2)
if norm(z) < eps(real(T))
return one(T)
Expand All @@ -91,7 +91,7 @@ function drummond0F1(β::T1, z::T2) where {T1, T2}
Dhi, Dmid, Dlo = ((β+k+1)*(k+2)*ζ-1)*Dhi + k*+2k+2)*ζ*Dmid + k*(k-1)*ζ*Dlo, Dhi, Dmid
Thi, Tmid, Tlo = Nhi/Dhi, Thi, Tmid
k += 1
while abs(Thi-Tmid) > 10*abs(Thi)*eps(real(T)) && abs(Tmid-Tlo) > 10*abs(Tmid)*eps(real(T)) && k < 10_000
while k < kmax && errcheck(Tmid, Thi, 10eps(real(T)))
Nhi, Nmid, Nlo = ((β+k+1)*(k+2)*ζ-1)*Nhi + k*+2k+2)*ζ*Nmid + k*(k-1)*ζ*Nlo, Nhi, Nmid
Dhi, Dmid, Dlo = ((β+k+1)*(k+2)*ζ-1)*Dhi + k*+2k+2)*ζ*Dmid + k*(k-1)*ζ*Dlo, Dhi, Dmid
Thi, Tmid, Tlo = Nhi/Dhi, Thi, Tmid
Expand All @@ -101,10 +101,10 @@ function drummond0F1(β::T1, z::T2) where {T1, T2}
end

# ₂F₀(α,β;z)
function drummond2F0::T1, β::T2, z::T3) where {T1, T2, T3}
function drummond2F0::T1, β::T2, z::T3; kmax::Int = 10_000) where {T1, T2, T3}
T = promote_type(T1, T2, T3)
absα = T(abs(α))
absβ = T(abs(β))
absα = abs(T(α))
absβ = abs(T(β))
if norm(z) < eps(real(T)) || norm*β) < eps(absα*absβ)
return one(T)
end
Expand All @@ -129,7 +129,7 @@ function drummond2F0(α::T1, β::T2, z::T3) where {T1, T2, T3}
Nhi /=+2)*+2)
Dhi /=+2)*+2)
k = 2
while abs(Thi-Tmid) > 10*abs(Thi)*eps(real(T)) && abs(Tmid-Tlo) > 10*abs(Tmid)*eps(real(T)) && k < 10_000
while k < kmax && errcheck(Tmid, Thi, 10eps(real(T)))
Nhi, Nmid, Nlo = ((k+2)*ζ-+k+1)*+k+1)-k*+β+2k+1))*Nhi - k*+β+3k-ζ)*Nmid - k*(k-1)*Nlo, Nhi, Nmid
Dhi, Dmid, Dlo = ((k+2)*ζ-+k+1)*+k+1)-k*+β+2k+1))*Dhi - k*+β+3k-ζ)*Dmid - k*(k-1)*Dlo, Dhi, Dmid
Thi, Tmid, Tlo = Nhi/Dhi, Thi, Tmid
Expand All @@ -144,9 +144,9 @@ function drummond2F0(α::T1, β::T2, z::T3) where {T1, T2, T3}
end

# ₁F₁(α,β;z)
function drummond1F1::T1, β::T2, z::T3) where {T1, T2, T3}
function drummond1F1::T1, β::T2, z::T3; kmax::Int = 10_000) where {T1, T2, T3}
T = promote_type(T1, T2, T3)
absα = T(abs(α))
absα = abs(T(α))
if norm(z) < eps(real(T)) || norm(α) < eps(absα)
return one(T)
end
Expand Down Expand Up @@ -180,7 +180,7 @@ function drummond1F1(α::T1, β::T2, z::T3) where {T1, T2, T3}
Nhi /= α+k+1
Dhi /= α+k+1
k += 1
while abs(Thi-Tmid) > 10*abs(Thi)*eps(real(T)) && abs(Tmid-Tlo) > 10*abs(Tmid)*eps(real(T)) && k < 10_000
while k < kmax && errcheck(Tmid, Thi, 10eps(real(T)))
Nhi, Nmid, Nlo = ((β+k+1)*(k+2)*ζ-+2k+1))*Nhi + k*((β+2k+2)*ζ-1)*Nmid + k*(k-1)*ζ*Nlo, Nhi, Nmid
Dhi, Dmid, Dlo = ((β+k+1)*(k+2)*ζ-+2k+1))*Dhi + k*((β+2k+2)*ζ-1)*Dmid + k*(k-1)*ζ*Dlo, Dhi, Dmid
Thi, Tmid, Tlo = Nhi/Dhi, Thi, Tmid
Expand All @@ -195,7 +195,7 @@ function drummond1F1(α::T1, β::T2, z::T3) where {T1, T2, T3}
end

# ₀F₂(α,β;z)
function drummond0F2::T1, β::T2, z::T3) where {T1, T2, T3}
function drummond0F2::T1, β::T2, z::T3; kmax::Int = 10_000) where {T1, T2, T3}
T = promote_type(T1, T2, T3)
if norm(z) < eps(real(T)) || norm(α) < eps(real(T)) || norm(β) < eps(real(T))
return one(T)
Expand All @@ -221,7 +221,7 @@ function drummond0F2(α::T1, β::T2, z::T3) where {T1, T2, T3}
Dhi, Dmid1, Dmid2, Dlo =*(k+2)*+k+1)*+k+1)-1)*Dhi + ζ*k*((k+1)*+β+2k)++k)*+k)+α+β+3k+2)*Dmid1 + ζ*k*(k-1)*(3k+α+β+1)*Dmid2 + ζ*k*(k-1)*(k-2)*Dlo, Dhi, Dmid1, Dmid2
Thi, Tmid1, Tmid2, Tlo = Nhi/Dhi, Thi, Tmid1, Tmid2
k += 1
while abs(Thi-Tmid1) > 10*abs(Thi)*eps(real(T)) && abs(Tmid1-Tmid2) > 10*abs(Tmid1)*eps(real(T)) && abs(Tmid2-Tlo) > 10*abs(Tmid2)*eps(real(T)) && k < 10_000
while k < kmax && errcheck(Tmid1, Thi, 10eps(real(T)))
Nhi, Nmid1, Nmid2, Nlo =*(k+2)*+k+1)*+k+1)-1)*Nhi + ζ*k*((k+1)*+β+2k)++k)*+k)+α+β+3k+2)*Nmid1 + ζ*k*(k-1)*(3k+α+β+1)*Nmid2 + ζ*k*(k-1)*(k-2)*Nlo, Nhi, Nmid1, Nmid2
Dhi, Dmid1, Dmid2, Dlo =*(k+2)*+k+1)*+k+1)-1)*Dhi + ζ*k*((k+1)*+β+2k)++k)*+k)+α+β+3k+2)*Dmid1 + ζ*k*(k-1)*(3k+α+β+1)*Dmid2 + ζ*k*(k-1)*(k-2)*Dlo, Dhi, Dmid1, Dmid2
Thi, Tmid1, Tmid2, Tlo = Nhi/Dhi, Thi, Tmid1, Tmid2
Expand All @@ -231,10 +231,10 @@ function drummond0F2(α::T1, β::T2, z::T3) where {T1, T2, T3}
end

# ₂F₁(α,β,γ;z)
function drummond2F1::T1, β::T2, γ::T3, z::T4) where {T1, T2, T3, T4}
function drummond2F1::T1, β::T2, γ::T3, z::T4; kmax::Int = 10_000) where {T1, T2, T3, T4}
T = promote_type(T1, T2, T3, T4)
absα = T(abs(α))
absβ = T(abs(β))
absα = abs(T(α))
absβ = abs(T(β))
if norm(z) < eps(real(T)) || norm*β) < eps(absα*absβ)
return one(T)
end
Expand Down Expand Up @@ -268,7 +268,7 @@ function drummond2F1(α::T1, β::T2, γ::T3, z::T4) where {T1, T2, T3, T4}
Nhi /=+k+1)*+k+1)
Dhi /=+k+1)*+k+1)
k += 1
while abs(Thi-Tmid) > 10*abs(Thi)*eps(real(T)) && abs(Tmid-Tlo) > 10*abs(Tmid)*eps(real(T)) && k < 10_000
while k < kmax && errcheck(Tmid, Thi, 10eps(real(T)))
Nhi, Nmid, Nlo = ((k+2)*+k+1)*ζ-+k+1)*+k+1)-k*+β+2k+1))*Nhi + k*((γ+2k+2)*ζ-+β+3k))*Nmid + k*(k-1)*-1)*Nlo, Nhi, Nmid
Dhi, Dmid, Dlo = ((k+2)*+k+1)*ζ-+k+1)*+k+1)-k*+β+2k+1))*Dhi + k*((γ+2k+2)*ζ-+β+3k))*Dmid + k*(k-1)*-1)*Dlo, Dhi, Dmid
Thi, Tmid, Tlo = Nhi/Dhi, Thi, Tmid
Expand All @@ -283,9 +283,9 @@ function drummond2F1(α::T1, β::T2, γ::T3, z::T4) where {T1, T2, T3, T4}
end

# ₘFₙ(α;β;z)
function drummondpFq::AbstractVector{T1}, β::AbstractVector{T2}, z::T3) where {T1, T2, T3}
function pFqdrummond::AbstractVector{T1}, β::AbstractVector{T2}, z::T3; kmax::Int = 10_000) where {T1, T2, T3}
T = promote_type(T1, T2, T3)
absα = T.(abs.(α))
absα = abs.(T.(α))
if norm(z) < eps(real(T)) || norm(prod(α)) < eps(prod(absα))
return one(T)
end
Expand All @@ -295,13 +295,15 @@ function drummondpFq(α::AbstractVector{T1}, β::AbstractVector{T2}, z::T3) wher
r = max(p+1, q+2)
C = zeros(T, r)
C[1] = one(T)
= zeros(T, r)
Ĉ[1] = one(T)
P = zeros(T, p+1)
t = one(T)
for j in 1:p
t *= α[j]+1
end
P[1] = t
err = one(T)
err = one(real(T))
for j in 1:p
err *= absα[j]+1
end
Expand All @@ -318,33 +320,37 @@ function drummondpFq(α::AbstractVector{T1}, β::AbstractVector{T2}, z::T3) wher
D[r+1] = prod(β)*ζ/prod(α)
R[r+1] = N[r+1]/D[r+1]
k = 0
while (abs(R[r+1]-R[r]) > 10*abs(R[r+1])*eps(real(T)) && k < 10_000) || k < r
while k < r || (k < kmax && errcheck(R[r], R[r+1], 10eps(real(T))))
for j in 1:r
N[j] = N[j+1]
D[j] = D[j+1]
R[j] = R[j+1]
end
t1 = zero(T)
for j in 0:min(k, q+1)
t1 += C[j+1]*Q[j+1]*N[r-j]
t1 += [j+1]*Q[j+1]*N[r-j]
end
if k q+1
t1 += Q[k+1]
if p > q
t1 += Q[k+1]
else
t1 += Q[k+1] / T(factorial(k+1))
end
end
t2 = zero(T)
t2 += P[1]*N[r]
t2 += Ĉ[1]*P[1]*N[r]
for j in 1:min(k, p)
t2 += C[j+1]*P[j+1]*(N[r-j+1]+N[r-j])
t2 += P[j+1]*(C[j+1]*N[r-j+1] + Ĉ[j+1]*N[r-j])
end
N[r+1] = ζ*t1-t2
t1 = zero(T)
for j in 0:min(k, q+1)
t1 += C[j+1]*Q[j+1]*D[r-j]
t1 += [j+1]*Q[j+1]*D[r-j]
end
t2 = zero(T)
t2 += P[1]*D[r]
t2 += Ĉ[1]*P[1]*D[r]
for j in 1:min(k, p)
t2 += C[j+1]*P[j+1]*(D[r-j+1]+D[r-j])
t2 += P[j+1]*(C[j+1]*D[r-j+1] + Ĉ[j+1]*D[r-j])
end
D[r+1] = ζ*t1-t2
R[r+1] = N[r+1]/D[r+1]
Expand All @@ -354,14 +360,23 @@ function drummondpFq(α::AbstractVector{T1}, β::AbstractVector{T2}, z::T3) wher
N[r+1] /= P[1]
D[r+1] /= P[1]
k += 1
for j in min(k, max(p, q+1)):-1:1
C[j+1] += C[j]
if p > q
for j in min(k, max(p, q+1)):-1:1
C[j+1] += C[j]
Ĉ[j+1] += Ĉ[j]
end
else
for j in min(k, max(p, q+1)):-1:1
C[j+1] = (C[j+1]*(k+1-j) + C[j])/(k+1)
Ĉ[j+1] = (Ĉ[j+1]*(k-j) + Ĉ[j])/(k+1)
end
Ĉ[1] = Ĉ[1]*k/(k+1)
end
t = one(T)
for j in 1:p
t *= α[j]+k+1
end
err = one(T)
err = one(real(T))
for j in 1:p
err *= absα[j]+k+1
end
Expand Down
Loading

2 comments on commit 123e404

@MikaelSlevinsky
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/17607

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.3.0 -m "<description of version>" 123e4040c5a8294b8d27b687a77d7fc112170944
git push origin v0.3.0

Please sign in to comment.