Skip to content

Commit 70ed13b

Browse files
AustenLamacraftdlfivefifty
authored andcommitted
Implementation of Bornemann's method for Tracy-Widom distributions (#44)
* Added Bornemann method * Added tests * tests passing * Adjust docstring * Updated REQUIRE * Removed dependency on OrdinaryDiffEq
1 parent e0db743 commit 70ed13b

File tree

4 files changed

+78
-52
lines changed

4 files changed

+78
-52
lines changed

REQUIRE

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
julia 0.6
22
Combinatorics 0.2
33
Distributions 0.8.10
4-
OrdinaryDiffEq 3.0.0
54
GSL 0.3.1
65
Compat 0.60
6+
SpecialFunctions 0.4.0
7+
FastGaussQuadrature 0.3.0

src/RandomMatrices.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ module RandomMatrices
22

33
using Combinatorics
44
using GSL
5-
using OrdinaryDiffEq
6-
using DiffEqBase # This line is only needed on v0.5, and comes free from OrdinaryDiffEq on v0.6
5+
using SpecialFunctions, FastGaussQuadrature
76

87
import Base: isinf, rand, convert
98
import Distributions: ContinuousUnivariateDistribution,

src/densities/TracyWidom.jl

Lines changed: 66 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,21 @@ export TracyWidom
44
Tracy-Widom distribution
55
66
The probability distribution of the normalized largest eigenvalue of a random
7-
Hermitian matrix.
7+
matrix with iid Gaussian matrix elements of variance 1/2 and mean 0.
88
99
The cdf of Tracy-Widom is given by
1010
1111
``
12-
F_2 (s) = lim_{n→∞} Pr(√2 n^{1/6} (λₙ - √(2n) ≤ s)
12+
F_beta (s) = lim_{n→∞} Pr(√2 n^{1/6} (λ_max - √(2n) ≤ s)
1313
``
1414
15+
where beta = 1, 2, or 4 for the orthogonal, unitary, or symplectic ensembles.
16+
1517
References:
1618
1719
1. doi:10.1016/0370-2693(93)91114-3
1820
2. doi:10.1007/BF02100489
21+
3. doi.org/10.1007/BF02099545
1922
2023
Numerical routines adapted from Alan Edelman's course notes for MIT 18.338,
2124
Random Matrix Theory, 2016.
@@ -24,59 +27,82 @@ struct TracyWidom <: ContinuousUnivariateDistribution end
2427

2528

2629
"""
27-
Probability density function of the Tracy-Widom distribution
30+
Cumulative density function of the Tracy-Widom distribution.
31+
32+
Computes the Tracy-Widom distribution by Bornemann's method of evaluating
33+
a finite dimensional approximation to the Fredholm determinant using quadrature.
2834
29-
Computes the Tracy-Widom distribution by directly solving the
30-
Painlevé II equation using the Vern8 numerical integrator
35+
doi.org/10.1090/S0025-5718-09-02280-7
3136
3237
# Arguments
3338
* `d::TracyWidom` or `Type{TracyWidom}`: an instance of `TracyWidom` or the type itself
34-
* `t::Real`: The point at which to evaluate the pdf
35-
* `t0::Real = -8.0`: The point at which to start integrating
39+
* `s::Real`: The point at which to evaluate the cdf
40+
* `beta::Integer = 2`: The Dyson index defining the distribution. Takes values 1, 2, or 4
41+
* `num_points::Integer = 25`: The number of points in the quadrature
3642
"""
37-
function pdf(d::TracyWidom, t::S, t0::S = convert(S, -8.0)) where {S<:Real}
38-
tt0 && return 0.0
39-
t5 && return 0.0
43+
function cdf{T<:Real}(d::TracyWidom, s::T; beta::Integer=2, num_points::Integer=25)
44+
beta (1,2,4) || throw(ArgumentError("Beta must be 1, 2, or 4"))
45+
quad = gausslegendre(num_points)
46+
_TWcdf(s, beta, quad)
47+
end
4048

41-
sol = _solve_painleve_ii(t0, t)
49+
function cdf{T<: Real}(d::Type{TracyWidom}, s::T; beta::Integer=2, num_points::Integer=25)
50+
cdf(d(), s, beta=beta, num_points=num_points)
51+
end
4252

43-
ΔF2=exp(-sol[end-1][3]) - exp(-sol[end][3]) # the cumulative distribution
44-
f2=ΔF2/(sol.t[end]-sol.t[end-1]) # the density at t
53+
function cdf{T<:Real}(d::TracyWidom, s_vals::AbstractArray{T}; beta::Integer=2, num_points::Integer=25)
54+
beta (1,2,4) || throw(ArgumentError("Beta must be 1, 2, or 4"))
55+
quad = gausslegendre(num_points)
56+
[_TWcdf(s, beta, quad) for s in s_vals]
4557
end
46-
pdf(d::Type{TracyWidom}, t::Real) = pdf(d(), t)
4758

48-
"""
49-
Cumulative density function of the Tracy-Widom distribution
59+
function cdf{T<:Real}(d::Type{TracyWidom}, s_vals::AbstractArray{T}; beta::Integer=2, num_points::Integer=25)
60+
cdf(d(), s_vals, beta=beta, num_points=num_points)
61+
end
5062

51-
Computes the Tracy-Widom distribution by directly solving the
52-
Painlevé II equation using the Vern8 numerical integrator
63+
function _TWcdf{T<:Real}(s::T, beta::Integer, quad::Tuple{Array{Float64,1},Array{Float64,1}})
64+
if beta == 2
65+
kernel = ((ξ,η) -> _K2tilde(ξ,η,s))
66+
return _fredholm_det(kernel, quad)
67+
elseif beta == 1
68+
kernel = ((ξ,η) -> _K1tilde(ξ,η,s))
69+
return _fredholm_det(kernel, quad)
70+
elseif beta == 4
71+
kernel2 = ((ξ,η) -> _K2tilde(ξ,η,s*sqrt(2)))
72+
kernel1 = ((ξ,η) -> _K1tilde(ξ,η,s*sqrt(2)))
73+
F2 = _fredholm_det(kernel2, quad)
74+
F1 = _fredholm_det(kernel1, quad)
75+
return (F1 + F2/F1) / 2
76+
end
77+
end
5378

54-
See `pdf(::TracyWidom)` for a description of the arguments.
55-
"""
56-
function cdf{S<:Real}(d::TracyWidom, t::S, t0::S = convert(S, -8.0))
57-
tt0 && return 0.0
58-
t5 && return 1.0
59-
sol = _solve_painleve_ii(t0, t)
60-
F2=exp(-sol[end][3])
79+
function _fredholm_det{T<:Real}(kernel::Function, quad::Tuple{Array{T,1},Array{T,1}})
80+
nodes, weights = quad
81+
N = length(nodes)
82+
sqrt_weights = sqrt.(weights)
83+
weights_matrix = kron(transpose(sqrt_weights),sqrt_weights)
84+
K_matrix = [kernel(ξ,η) for ξ in nodes, η in nodes]
85+
det(eye(N) - weights_matrix .* K_matrix)
6186
end
62-
cdf(d::Type{TracyWidom}, t::Real) = cdf(d(), t)
63-
64-
# An internal function which sets up the Painleve II differential equation and
65-
# runs it through the Vern8 numerical integrator
66-
function _solve_painleve_ii{S<:Real}(t0::S, t::S)
67-
function deq(dy, y, p, t)
68-
dy[1] = y[2]
69-
dy[2] = t*y[1]+2y[1]^3
70-
dy[3] = y[4]
71-
dy[4] = y[1]^2
87+
88+
(ξ, s) = s + 10*tan*+1)/4)
89+
_ϕprime(ξ) = (5π/2)*(sec*+1)/4))^2
90+
91+
# For beta = 2
92+
function _airy_kernel(x, y)
93+
if x==y
94+
return (airyaiprime(x))^2 - x * (airyai(x))^2
95+
else
96+
return (airyai(x) * airyaiprime(y) - airyai(y) * airyaiprime(x)) / (x - y)
7297
end
73-
a0 = airyai(t0)
74-
T = typeof(big(a0))
75-
y0=T[a0, airyaiprime(t0), 0, airyai(t0)^2] # Initial conditions
76-
prob = ODEProblem(deq,y0,(t0,t))
77-
solve(prob, Vern8(), abstol=1e-12, reltol=1e-12) # Solve the ODE
7898
end
7999

100+
_K2tilde(ξ,η,s) = sqrt(_ϕprime(ξ) * _ϕprime(η)) * _airy_kernel((ξ,s), (η,s))
101+
102+
# For beta = 1
103+
_A_kernel(x,y) = airyai((x+y)/2) / 2
104+
_K1tilde(ξ,η,s) = sqrt(_ϕprime(ξ) * _ϕprime(η)) * _A_kernel((ξ,s), (η,s))
105+
80106
"""
81107
Samples the largest eigenvalue of the n × n GUE matrix
82108
"""

test/densities/TracyWidom.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
using RandomMatrices
22
using Compat.Test
33

4+
# CDF lies in correct range
5+
@test all(i->(0<i<1), cdf(TracyWidom, randn(5)))
6+
47
#Test far outside support
5-
#Tracy-Widom has support on all x>0, but the integration won't pick it up
6-
@test pdf(TracyWidom, -10) == pdf(TracyWidom, 10) == 0
7-
@test cdf(TracyWidom, -10) == 0
8-
@test cdf(TracyWidom, 10) == 1
8+
@test cdf(TracyWidom, -10.1) 0 atol=1e-14
9+
@test cdf(TracyWidom, 10.1) 1 atol=1e-14
910

10-
if isdefined(:OrdinaryDiffEq) && isa(OrdinaryDiffEq, Module)
11-
t = rand()
12-
@test pdf(TracyWidom, t) > 0
13-
@test 0 < cdf(TracyWidom, t) < 1
14-
end
11+
# Test exact values
12+
# See https://arxiv.org/abs/0904.1581
13+
@test cdf(TracyWidom,0,beta=1) 0.83190806620295 atol=1e-14
14+
@test cdf(TracyWidom,0,beta=2) 0.96937282835526 atol=1e-14
1515

1616
@test isfinite(rand(TracyWidom, 10))
1717
@test isfinite(rand(TracyWidom, 100))

0 commit comments

Comments
 (0)