|
13 | 13 | # Alan Edelman, Per-Olof Persson and Brian D Sutton, "The fourfold way"
|
14 | 14 | # http://www-math.mit.edu/~edelman/homepage/papers/ffw.pdf
|
15 | 15 |
|
| 16 | +import Distributions: Chisq |
| 17 | +import Base: isinf, rand |
16 | 18 | export GaussianHermite, GaussianLaguerre, GaussianJacobi,
|
17 | 19 | Wigner, Wishart, MANOVA #Synonyms for Hermite, Laguerre and Jacobi
|
18 | 20 |
|
19 | 21 | #A convenience function to define a chi scalar random variable
|
20 |
| -chi(df::Real) = sqrt(rand(Chisq(df))) |
| 22 | +χ(df::Real) = √(rand(Chisq(df))) |
21 | 23 |
|
22 | 24 | #####################
|
23 | 25 | # Hermite ensemble #
|
24 | 26 | #####################
|
25 | 27 |
|
26 |
| -type GaussianHermite <: ContinuousMatrixDistribution |
27 |
| - beta::Real |
28 |
| -end |
29 |
| -typealias Wigner GaussianHermite |
| 28 | +""" |
| 29 | +GaussianHermite{β} represents a Gaussian Hermite ensemble with parameter β. |
30 | 30 |
|
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) |
34 | 55 | 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) |
36 | 61 | 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) |
38 | 67 | #Employs 2x2 matrix representation of quaternions
|
39 | 68 | X = randn(n, n) + im*randn(n, n)
|
40 | 69 | Y = randn(n, n) + im*randn(n, n)
|
41 | 70 | 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) |
47 | 73 | end
|
48 | 74 |
|
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 β=$β")) |
50 | 77 |
|
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 |
60 | 84 | end
|
61 | 85 |
|
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) |
74 | 103 | end
|
75 |
| - end |
76 |
| - Vandermonde |
77 | 104 | 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 |
88 | 111 | end
|
89 | 112 |
|
| 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 |
90 | 129 |
|
| 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 |
91 | 143 |
|
92 | 144 | #####################
|
93 | 145 | # Laguerre ensemble #
|
|
0 commit comments