Skip to content

Commit c75e471

Browse files
committed
Modernize Wigner GaussianHermite code
Make β a type parameter, facilitating dispatch Put documentation in docstrings where possible Tests! Ref: #15
1 parent 9fddb0e commit c75e471

File tree

3 files changed

+129
-49
lines changed

3 files changed

+129
-49
lines changed

src/GaussianEnsembles.jl

Lines changed: 101 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,81 +13,133 @@
1313
# Alan Edelman, Per-Olof Persson and Brian D Sutton, "The fourfold way"
1414
# http://www-math.mit.edu/~edelman/homepage/papers/ffw.pdf
1515

16+
import Distributions: Chisq
17+
import Base: isinf, rand
1618
export GaussianHermite, GaussianLaguerre, GaussianJacobi,
1719
Wigner, Wishart, MANOVA #Synonyms for Hermite, Laguerre and Jacobi
1820

1921
#A convenience function to define a chi scalar random variable
20-
chi(df::Real) = sqrt(rand(Chisq(df)))
22+
χ(df::Real) = (rand(Chisq(df)))
2123

2224
#####################
2325
# Hermite ensemble #
2426
#####################
2527

26-
type GaussianHermite <: ContinuousMatrixDistribution
27-
beta::Real
28-
end
29-
typealias Wigner GaussianHermite
28+
"""
29+
GaussianHermite{β} represents a Gaussian Hermite ensemble with parameter β.
3030
31-
# Generates a NxN symmetric Wigner matrix
32-
function rand(d::GaussianHermite, n::Integer)
33-
if d.beta == 1 #real
31+
Wigner{β} is a synonym.
32+
33+
Example of usage:
34+
35+
β = 2 #β = 1, 2, 4 generates real, complex and quaternionic matrices respectively.
36+
d = Wigner{β} #same as GaussianHermite{β}
37+
38+
n = 20 #Generate square matrices of this size
39+
40+
S = rand(d, n) #Generate a 20x20 symmetric Wigner matrix
41+
T = tridrand(d, n) #Generate the symmetric tridiagonal form
42+
v = eigvalrand(d, n) #Generate a sample of eigenvalues
43+
"""
44+
immutable GaussianHermite{β} <: ContinuousMatrixDistribution end
45+
GaussianHermite(β) = GaussianHermite{β}()
46+
47+
"""
48+
Synonym for GaussianHermite{β}
49+
"""
50+
typealias Wigner{β} GaussianHermite{β}
51+
52+
rand{β}(d::Type{Wigner{β}}, dims...) = rand(d(), dims...)
53+
54+
function rand(d::Wigner{1}, n::Int)
3455
A = randn(n, n)
35-
elseif d.beta == 2 #complex
56+
normalization = (2*n)
57+
return Symmetric((A + A') / normalization)
58+
end
59+
60+
function rand(d::Wigner{2}, n::Int)
3661
A = randn(n, n) + im*randn(n, n)
37-
elseif d.beta == 4 #quaternion
62+
normalization = (4*n)
63+
return Hermitian((A + A') / normalization)
64+
end
65+
66+
function rand(d::Wigner{4}, n::Int)
3867
#Employs 2x2 matrix representation of quaternions
3968
X = randn(n, n) + im*randn(n, n)
4069
Y = randn(n, n) + im*randn(n, n)
4170
A = [X Y; -conj(Y) conj(X)]
42-
else
43-
error(@sprintf("beta = %d is not implemented", d.beta))
44-
end
45-
normalization = sqrt(2*d.beta*n)
46-
return (A + A') / normalization
71+
normalization = (8*n)
72+
return Hermitian((A + A') / normalization)
4773
end
4874

49-
rand(d::GaussianHermite, dims::Dim2) = dims[1]==dims[2] ? rand(d, dims[1]) : error("Can only generate square matrices")
75+
rand{β}(d::Wigner{β}, n::Int) =
76+
throw(ValueError("Cannot sample random matrix of size $n x $n for β="))
5077

51-
52-
#Generates a NxN tridiagonal Wigner matrix
53-
#The beta=infinity case is defined in Edelman, Persson and Sutton, 2012
54-
function tridrand(d::GaussianHermite, n::Integer)
55-
if d.beta<=0 error("beta must be positive") end
56-
if d.beta==Inf return SymTridiagonal(zeros(n), [sqrt(x/2) for x=n-1:-1:1]) end
57-
Hdiag = randn(n)/sqrt(n)
58-
Hsup = [chi(d.beta*i)/sqrt(2*n) for i=n-1:-1:1]
59-
return SymTridiagonal(Hdiag, Hsup)
78+
function rand{β}(d::Wigner{β}, dims...)
79+
if length(dims)==2 && dims[1] == dims[2]
80+
return rand(d, dims[1])
81+
else
82+
throw(ValueError("Cannot sample random matrix of size $dims for β="))
83+
end
6084
end
6185

62-
tridrand(d::GaussianHermite, dims::Dim2) = dims[1]==dims[2] ? tridrand(d, dims[1]) : error("Can only generate square matrices")
63-
64-
#Return n eigenvalues distributed according to the Hermite ensemble
65-
eigvalrand(d::GaussianHermite, n::Integer) = eigvals(tridrand(d, n))
66-
67-
#Calculate Vandermonde determinant term
68-
function VandermondeDeterminant{Eigenvalue<:Number}(lambda::Vector{Eigenvalue}, beta::Real)
69-
n = length(lambda)
70-
Vandermonde = 1.0
71-
for j=1:n
72-
for i=1:j-1
73-
Vandermonde *= abs(lambda[i] - lambda[j])^beta
86+
"""
87+
Generates a nxn symmetric tridiagonal Wigner matrix
88+
89+
Unlike for `rand(Wigner{β}, n)`, which is restricted to β=1,2 or 4,
90+
`trirand(Wigner{β}, n)` will generate a
91+
92+
The β=∞ case is defined in Edelman, Persson and Sutton, 2012
93+
"""
94+
function tridrand{β}(d::Wigner{β}, n::Int)
95+
if β0
96+
throw(ValueError("β = cannot be nonpositive"))
97+
elseif isinf(β)
98+
return tridrand(Wigner{Inf}, n)
99+
else
100+
Hd = randn(n)/√(n)
101+
He = [χ*i)/√(2*n) for i=n-1:-1:1]
102+
return SymTridiagonal(Hd, He)
74103
end
75-
end
76-
Vandermonde
77104
end
78-
79-
function eigvaljpdf{Eigenvalue<:Number}(d::GaussianHermite, lambda::Vector{Eigenvalue})
80-
n = length(lambda)
81-
#Calculate normalization constant
82-
c = (2pi)^(-n/2)
83-
for j=1:n
84-
c *= gamma(1 + beta/2)/gamma(1 + beta*j/2)
85-
end
86-
Energy = sum(lambda.^2/2) #Calculate argument of exponential
87-
VandermondeDeterminant(lambda, beta) * exp(-Energy)
105+
function tridrand{β}(d::Wigner{β}, dims...)
106+
if length(dims)==2 && dims[1] == dims[2]
107+
return rand(d, dims[1])
108+
else
109+
throw(ValueError("Cannot sample random matrix of size $dims for β="))
110+
end
88111
end
89112

113+
"""
114+
Return n eigenvalues distributed according to the Hermite ensemble
115+
"""
116+
eigvalrand(d::Wigner, n::Int) = eigvals(tridrand(d, n))
117+
118+
"""
119+
Calculate Vandermonde determinant term
120+
"""
121+
function VandermondeDeterminant{Eigenvalue<:Number}::AbstractVector{Eigenvalue}, β::Real)
122+
n = length(λ)
123+
Vandermonde = one(Eigenvalue)^β
124+
for j=1:n, i=1:j-1
125+
Vandermonde *= abs(λ[i] - λ[j])^β
126+
end
127+
Vandermonde
128+
end
90129

130+
"""
131+
Calculate joint eigenvalue density
132+
"""
133+
function eigvaljpdf{β,Eigenvalue<:Number}(d::Wigner{β}, λ::AbstractVector{Eigenvalue})
134+
n = length(λ)
135+
#Calculate normalization constant
136+
c = (2π)^(-n/2)
137+
for j=1:n
138+
c *= gamma(1 + β/2)/gamma(1 + β*j/2)
139+
end
140+
Energy = sum.^2/2) #Calculate argument of exponential
141+
VandermondeDeterminant(λ, β) * exp(-Energy)
142+
end
91143

92144
#####################
93145
# Laguerre ensemble #

test/GaussianEnsembles.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Base.Test
2+
using RandomMatrices
3+
4+
@test Wigner{3} == GaussianHermite{3}
5+
6+
n = 25
7+
8+
for (β, T, N) in [(1, Real, n), (2, Complex, n), (4, Complex, 2n)]
9+
d = Wigner(β)
10+
A = rand(d, n)
11+
@test eltype(A) <: T
12+
@test size(A) == (N, N)
13+
14+
At = tridrand(d, n)
15+
@test eltype(At) <: Real
16+
@test size(At) == (n, n)
17+
18+
vals = eigvalrand(d, n)
19+
@test eltype(vals) <: Real
20+
@test length(vals) == n
21+
22+
vd = RandomMatrices.VandermondeDeterminant(vals, β)
23+
@test isa(vd, Real)
24+
25+
ed = eigvaljpdf(d, vals)
26+
@test isa(ed, Real)
27+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ using RandomMatrices
22
using Base.Test
33

44
srand(1)
5+
include("GaussianEnsembles.jl")
56
include("FormalPowerSeries.jl")
67
include("Haar.jl")
78
include("StochasticProcess.jl")

0 commit comments

Comments
 (0)