Skip to content

Commit 37f177b

Browse files
authored
Fix rand(d::GaussianLaguerre, n::Int), improve performance, add tests (#93)
* fix/optimize `rand(d::GaussianLaguerre, n::Int)` * add simple Wishart tests
1 parent fc98f3b commit 37f177b

File tree

2 files changed

+84
-34
lines changed

2 files changed

+84
-34
lines changed

src/GaussianEnsembles.jl

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,20 @@ used to control the density of eigenvalues near `λ = 0`.
169169
- `beta`: Dyson index
170170
- `a`: Parameter used for weighting the joint probability density function of the ensemble
171171
172+
## Examples
173+
```@example
174+
julia> rand(GaussianLaguerre(1, 2), 2)
175+
2×2 Matrix{Float64}:
176+
5.08544 -0.156801
177+
-0.156801 3.17245
178+
179+
julia> rand(GaussianLaguerre(4, 8), 2)
180+
4×4 Matrix{ComplexF64}:
181+
2.66965+0.0im 0.616044-0.336025im -8.48419e-18-2.17815e-17im 0.661922-0.190965im
182+
0.616044+0.336025im 3.27444+0.0im -0.661922+0.190965im -1.239e-17+8.84953e-17im
183+
-8.48419e-18+2.17815e-17im -0.661922-0.190965im 2.66965+0.0im 0.616044+0.336025im
184+
0.661922+0.190965im -1.239e-17-8.84953e-17im 0.616044-0.336025im 3.27444+0.0im
185+
```
172186
## References:
173187
- Edelman and Rao, 2005
174188
"""
@@ -181,27 +195,39 @@ const Wishart = GaussianLaguerre
181195
#TODO Check - the eigenvalue distribution looks funky
182196
#TODO The appropriate matrix size should be calculated from a and one matrix dimension
183197
"""
184-
rand(d::GaussianLaguerre, dims::Tuple)
198+
rand(d::GaussianLaguerre, n::Int)
185199
186200
Generate a random matrix sampled from the Gaussian Laguerre ensemble (also known as the Wishart ensemble)
187-
with parameters defined in `d` and dimensions given by `dims`.
201+
with parameters defined in `d`.
188202
189-
The Dyson index `β` is restricted to `β = 1,2` or `4`, for real, complex, and quaternionic fields, respectively.
203+
The Dyson index `β` is restricted to `β = 1,2` (`n × n` matrix) or `4` (`2n × 2n` block matrix representation),
204+
for real, complex, and quaternionic fields, respectively.
190205
"""
191-
function rand(d::GaussianLaguerre, dims::Dim2)
192-
n = 2.0*a/d.beta
193-
if d.beta == 1 #real
194-
A = randn(dims)
195-
elseif d.beta == 2 #complex
196-
A = randn(dims) + im*randn(dims)
197-
elseif d.beta == 4 #quaternion
198-
#Employs 2x2 matrix representation of quaternions
199-
X = randn(dims) + im*randn(dims)
200-
Y = randn(dims) + im*randn(dims)
201-
A = [X Y; -conj(Y) conj(X)]
202-
error("beta = $(d.beta) is not implemented")
206+
function rand(d::GaussianLaguerre, n::Int)
207+
a, beta = d.a, d.beta
208+
a >= beta * n / 2 || throw(ArgumentError("the minimum value of `a` must be `βn/2`."))
209+
m = Int(2*a/beta)
210+
if beta == 1 # real
211+
A = randn(m, n)
212+
elseif beta == 2 # complex
213+
A = randn(ComplexF64, m, n)
214+
elseif beta == 4 # quaternion
215+
# employs 2x2 matrix representation of quaternions
216+
X = randn(ComplexF64, m, n)
217+
Y = randn(ComplexF64, m, n)
218+
A = Matrix{ComplexF64}(undef, 2m, 2n)
219+
@inbounds for j in 1:n, i in 1:m
220+
x = X[i, j]
221+
y = Y[i, j]
222+
A[i, j] = x
223+
A[i+m, j] = -conj(y)
224+
A[i, j+n] = y
225+
A[i+m, j+n] = conj(x)
226+
end
227+
else
228+
error("beta = $(beta) is not implemented")
203229
end
204-
return (A * A') / dims[1]
230+
return (A' * A) / n
205231
end
206232

207233
"""

test/GaussianEnsembles.jl

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,52 @@ using Test
44
@testset "GaussianEnsembles" begin
55

66
@test Wigner{3} == GaussianHermite{3}
7+
@test Wishart == GaussianLaguerre
78

89
n = 25
910

1011
for (β, T, N) in [(1, Real, n), (2, Complex, n), (4, Complex, 2n)]
11-
d = Wigner(β)
12-
A = rand(d, n)
13-
@test eltype(A) <: T
14-
@test size(A) == (N, N)
15-
16-
At = tridrand(d, n)
17-
@test eltype(At) <: Real
18-
@test size(At) == (n, n)
19-
20-
vals = eigvalrand(d, n)
21-
@test eltype(vals) <: Real
22-
@test length(vals) == n
23-
24-
vd = RandomMatrices.VandermondeDeterminant(vals, β)
25-
@test isa(vd, Real)
26-
27-
ed = eigvaljpdf(d, vals)
28-
@test isa(ed, Real)
12+
@testset "Wigner (β = $(β))" begin
13+
d = Wigner(β)
14+
A = rand(d, n)
15+
@test eltype(A) <: T
16+
@test size(A) == (N, N)
17+
18+
At = tridrand(d, n)
19+
@test eltype(At) <: Real
20+
@test size(At) == (n, n)
21+
22+
vals = eigvalrand(d, n)
23+
@test eltype(vals) <: Real
24+
@test length(vals) == n
25+
26+
vd = RandomMatrices.VandermondeDeterminant(vals, β)
27+
@test isa(vd, Real)
28+
29+
ed = eigvaljpdf(d, vals)
30+
@test isa(ed, Real)
31+
end
32+
@testset "Wishart (β = $(β))" begin
33+
a = 2(rand(1:5) + β * n)
34+
d = Wishart(β, a)
35+
A = rand(d, n)
36+
@test eltype(A) <: T
37+
@test size(A) == (N, N)
38+
39+
@test_throws UndefVarError tridrand(d, n) # = At
40+
#@test eltype(At) <: Real
41+
#@test size(At) == (n, n)
42+
43+
@test_throws UndefVarError eigvalrand(d, n) # = vals
44+
#@test eltype(vals) <: Real
45+
#@test length(vals) == n
46+
47+
#vd = RandomMatrices.VandermondeDeterminant(vals, β)
48+
#@test isa(vd, Real)
49+
50+
#ed = eigvaljpdf(d, vals)
51+
#@test isa(ed, Real)
52+
end
2953
end
3054

3155
end # testset

0 commit comments

Comments
 (0)