@@ -24,11 +24,12 @@ export GaussianHermite, GaussianLaguerre, GaussianJacobi,
24
24
# ####################
25
25
26
26
"""
27
- GaussianHermite(β::Int) <: ContinuousMatrixDistribution
27
+ GaussianHermite{β} <: ContinuousMatrixDistribution
28
+ GaussianHermite(β::Real) -> GaussianHermite{β}()
28
29
29
30
Represents a Gaussian Hermite ensemble with Dyson index `β`.
30
31
31
- `Wigner(β) ` is a synonym.
32
+ `Wigner{β} ` is a synonym.
32
33
33
34
## Examples
34
35
@@ -41,15 +42,15 @@ julia> rand(Wigner(2), 3)
41
42
```
42
43
"""
43
44
struct GaussianHermite{β} <: ContinuousMatrixDistribution end
44
- GaussianHermite (β) = GaussianHermite {β} ()
45
+ GaussianHermite (β:: Real ) = GaussianHermite {β} ()
45
46
46
47
"""
47
48
Synonym for GaussianHermite{β}
48
49
"""
49
50
const Wigner{β} = GaussianHermite{β}
50
51
51
52
"""
52
- rand(d::Wigner, n::Int)
53
+ rand(d::Wigner{β} , n::Int)
53
54
54
55
Generates an `n × n` matrix randomly sampled from the Gaussian-Hermite ensemble (also known as the Wigner ensemble).
55
56
@@ -64,16 +65,24 @@ function rand(d::Wigner{1}, n::Int)
64
65
end
65
66
66
67
function rand (d:: Wigner{2} , n:: Int )
67
- A = randn (n, n) + im * randn ( n, n)
68
+ A = randn (ComplexF64, n, n)
68
69
normalization = √ (4 * n)
69
70
return Hermitian ((A + A' ) / normalization)
70
71
end
71
72
72
73
function rand (d:: Wigner{4} , n:: Int )
73
74
# Employs 2x2 matrix representation of quaternions
74
- X = randn (n, n) + im* randn (n, n)
75
- Y = randn (n, n) + im* randn (n, n)
76
- A = [X Y; - conj (Y) conj (X)]
75
+ X = randn (ComplexF64, n, n)
76
+ Y = randn (ComplexF64, n, n)
77
+ A = Matrix {ComplexF64} (undef, 2 n, 2 n)
78
+ @inbounds for j in 1 : n, i in 1 : n
79
+ x = X[i, j]
80
+ y = Y[i, j]
81
+ A[i, j] = x
82
+ A[i+ n, j] = - conj (y)
83
+ A[i, j+ n] = y
84
+ A[i+ n, j+ n] = conj (x)
85
+ end
77
86
normalization = √ (8 * n)
78
87
return Hermitian ((A + A' ) / normalization)
79
88
end
@@ -90,7 +99,7 @@ function rand(d::Wigner{β}, dims::Int...) where {β}
90
99
end
91
100
92
101
"""
93
- tridand(d::Wigner, n::Int)
102
+ tridand(d::Wigner{β} , n::Int)
94
103
95
104
Generates an `n × n` symmetric tridiagonal matrix from the Gaussian-Hermite ensemble (also known as the Wigner ensemble).
96
105
@@ -158,15 +167,15 @@ end
158
167
# ####################
159
168
160
169
"""
161
- GaussianLaguerre(β::Real, a::Real)` <: ContinuousMatrixDistribution
170
+ GaussianLaguerre{β}(a::Real)` <: ContinuousMatrixDistribution
171
+ GaussianLaguerre(β::Real, a::Real) -> GaussianLaguerre{β}(a)
162
172
163
173
Represents a Gaussian-Laguerre ensemble with Dyson index `β` and `a` parameter
164
174
used to control the density of eigenvalues near `λ = 0`.
165
175
166
- `Wishart(β, a)` is a synonym.
176
+ `Wishart{β}( a)` is a synonym.
167
177
168
178
## Fields
169
- - `beta`: Dyson index
170
179
- `a`: Parameter used for weighting the joint probability density function of the ensemble
171
180
172
181
## Examples
@@ -186,32 +195,41 @@ julia> rand(GaussianLaguerre(4, 8), 2)
186
195
## References:
187
196
- Edelman and Rao, 2005
188
197
"""
189
- mutable struct GaussianLaguerre <: ContinuousMatrixDistribution
190
- beta:: Real
198
+ struct GaussianLaguerre{β} <: ContinuousMatrixDistribution
191
199
a:: Real
192
200
end
193
- const Wishart = GaussianLaguerre
201
+ GaussianLaguerre (β:: Real , a:: Real ) = GaussianLaguerre {β} (a:: Real )
202
+ const Wishart{β} = GaussianLaguerre{β}
194
203
195
204
# TODO Check - the eigenvalue distribution looks funky
196
205
# TODO The appropriate matrix size should be calculated from a and one matrix dimension
197
206
"""
198
- rand(d::GaussianLaguerre, n::Int)
207
+ rand(d::GaussianLaguerre{β} , n::Int)
199
208
200
209
Generate a random matrix sampled from the Gaussian Laguerre ensemble (also known as the Wishart ensemble)
201
210
with parameters defined in `d`.
202
211
203
212
The Dyson index `β` is restricted to `β = 1,2` (`n × n` matrix) or `4` (`2n × 2n` block matrix representation),
204
213
for real, complex, and quaternionic fields, respectively.
205
214
"""
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
215
+ function rand (d:: GaussianLaguerre{1} , n:: Int )
216
+ a = d. a
217
+ a >= n / 2 || throw (ArgumentError (" the minimum value of `a` must be `βn/2`." ))
218
+ m = Int (2 a)
211
219
A = randn (m, n)
212
- elseif beta == 2 # complex
220
+ return (A' * A) / n
221
+ end
222
+ function rand (d:: GaussianLaguerre{2} , n:: Int )
223
+ a = d. a
224
+ a >= n || throw (ArgumentError (" the minimum value of `a` must be `βn/2`." ))
225
+ m = Int (2 a)
213
226
A = randn (ComplexF64, m, n)
214
- elseif beta == 4 # quaternion
227
+ return (A' * A) / n
228
+ end
229
+ function rand (d:: GaussianLaguerre{4} , n:: Int )
230
+ a = d. a
231
+ a >= 2 n || throw (ArgumentError (" the minimum value of `a` must be `βn/2`." ))
232
+ m = Int (2 a)
215
233
# employs 2x2 matrix representation of quaternions
216
234
X = randn (ComplexF64, m, n)
217
235
Y = randn (ComplexF64, m, n)
@@ -224,26 +242,24 @@ function rand(d::GaussianLaguerre, n::Int)
224
242
A[i, j+ n] = y
225
243
A[i+ m, j+ n] = conj (x)
226
244
end
227
- else
228
- error (" beta = $(beta) is not implemented" )
229
- end
230
- return (A' * A) / n
245
+ return (A' * A) / n
231
246
end
247
+ rand (d:: GaussianLaguerre{β} , n:: Int ) where {β} = throw (ArgumentError (" beta = $(β) is not implemented" ))
232
248
233
249
"""
234
- bidrand(d::GaussianLaguerre, n::Int)
250
+ bidrand(d::GaussianLaguerre{β} , n::Int)
235
251
236
252
Generate an `n × n` bidiagonal matrix sampled from the Gaussian Laguerre ensemble (also known as the Wishart ensemble).
237
253
"""
238
- function bidrand (d:: GaussianLaguerre , m:: Integer )
239
- if d. a <= d . beta * (m- 1 )/ 2.0
240
- error (" Given your choice of m and beta, a must be at least $(d . beta * (m- 1 )/ 2.0 ) (You said a = $(d. a) )" )
254
+ function bidrand (d:: GaussianLaguerre{β} , m:: Integer ) where {β}
255
+ if d. a <= β * (m- 1 )/ 2.0
256
+ error (" Given your choice of m and beta, a must be at least $(β * (m- 1 )/ 2.0 ) (You said a = $(d. a) )" )
241
257
end
242
- Bidiagonal ([chi (2 * d. a- i* d . beta ) for i= 0 : m- 1 ], [chi (d . beta * i) for i= m- 1 : - 1 : 1 ], true )
258
+ Bidiagonal ([chi (2 * d. a- i* β ) for i= 0 : m- 1 ], [chi (β * i) for i= m- 1 : - 1 : 1 ], true )
243
259
end
244
260
245
261
"""
246
- tridrand(d::GaussianLaguerre, n::Int)
262
+ tridrand(d::GaussianLaguerre{β} , n::Int)
247
263
248
264
Generate an `n × n` tridiagonal matrix sampled from the Gaussian Laguerre ensemble (also known as the Wishart ensemble).
249
265
"""
@@ -257,25 +273,25 @@ end
257
273
eigvalrand (d:: GaussianLaguerre , m:: Integer ) = eigvals (tridrand (d, m))
258
274
259
275
# TODO Check m and ns
260
- function eigvaljpdf (d:: GaussianLaguerre , lambda:: Vector{Eigenvalue} ) where {Eigenvalue<: Number }
276
+ function eigvaljpdf (d:: GaussianLaguerre{β} , lambda:: Vector{Eigenvalue} ) where {β, Eigenvalue<: Number }
261
277
m = length (lambda)
262
278
# Laguerre parameters
263
- p = 0.5 * d . beta * (m- 1 ) + 1.0
279
+ p = 0.5 * β * (m- 1 ) + 1.0
264
280
# Calculate normalization constant
265
281
c = 2.0 ^- (m* d. a)
266
- z = (d. a - d . beta * (m)* 0.5 )
282
+ z = (d. a - β * (m)* 0.5 )
267
283
for j= 1 : m
268
- z += 0.5 * d . beta
284
+ z += 0.5 * β
269
285
if z < 0 && (int (z) - z) < eps ()
270
286
# Pole of gamma function, there is no density here no matter what
271
287
return 0.0
272
288
end
273
- c *= gamma (1 + beta / 2 )/ (gamma (1 + beta * j/ 2 )* gamma (z))
289
+ c *= gamma (1 + β / 2 )/ (gamma (1 + β * j/ 2 )* gamma (z))
274
290
end
275
291
276
- Prod = prod (lambda.^ (a- p)) # Calculate Laguerre product term
292
+ Prod = prod (lambda.^ (d . a- p)) # Calculate Laguerre product term
277
293
Energy = sum (lambda)/ 2 # Calculate argument of exponential
278
- return c * VandermondeDeterminant (lambda, beta ) * Prod * exp (- Energy)
294
+ return c * VandermondeDeterminant (lambda, β ) * Prod * exp (- Energy)
279
295
end
280
296
281
297
@@ -285,37 +301,37 @@ end
285
301
# ##################
286
302
287
303
"""
288
- GaussianJacobi(β::Real, a::Real, a::Real)` <: ContinuousMatrixDistribution
304
+ GaussianJacobi{β}(a::Real, b::Real) <: ContinuousMatrixDistribution
305
+ GaussianJacobi(β::Real, a::Real, b::Real) -> GaussianJacobi{β}(a, b)
289
306
290
307
Represents a Gaussian-Jacobi ensemble with Dyson index `β`, while
291
308
`a`and `b` are parameters used to weight the joint probability density function of the ensemble.
292
309
293
- `MANOVA(β, a, b)` is a synonym.
310
+ `MANOVA{β}( a, b)` is a synonym.
294
311
295
312
## Fields
296
- - `beta`: Dyson index
297
313
- `a`: Parameter used for shaping the joint probability density function near `λ = 0`
298
314
- `b`: Parameter used for shaping the joint probability density function near `λ = 1`
299
315
300
316
## References:
301
317
- Edelman and Rao, 2005
302
318
"""
303
- mutable struct GaussianJacobi <: ContinuousMatrixDistribution
304
- beta:: Real
319
+ struct GaussianJacobi{β} <: ContinuousMatrixDistribution
305
320
a:: Real
306
321
b:: Real
307
322
end
308
- const MANOVA = GaussianJacobi
323
+ GaussianJacobi (β:: Real , a:: Real , b:: Real ) = GaussianJacobi {β} (a, b)
324
+ const MANOVA{β} = GaussianJacobi{β}
309
325
310
326
"""
311
- rand(d::GaussianJacobi, n::Int)
327
+ rand(d::GaussianJacobi{β} , n::Int)
312
328
313
329
Generate an `n × n` random matrix sampled from the Gaussian-Jacobi ensemble (also known as the MANOVA ensemble)
314
330
with parameters defined in `d`.
315
331
"""
316
- function rand (d:: GaussianJacobi , m :: Integer )
317
- w1 = Wishart (m, int ( 2.0 * d. a/ d . beta ), d . beta )
318
- w2 = Wishart (m, int ( 2.0 * d. b/ d . beta ), d . beta )
332
+ function rand (d:: GaussianJacobi{β} , n :: Int ) where {β}
333
+ w1 = rand ( Wishart (β, d. a), n )
334
+ w2 = rand ( Wishart (β, d. b), n )
319
335
return (w1 + w2) \ w1
320
336
end
321
337
@@ -346,12 +362,12 @@ end
346
362
# and generalized singular value problems", Foundations of Computational Mathematics,
347
363
# vol. 8 iss. 2 (2008), pp 259-285.
348
364
# TODO check normalization
349
- function sprand (d:: GaussianJacobi , n:: Integer , a:: Real , b:: Real )
365
+ function sprand (d:: GaussianJacobi{β} , n:: Integer , a:: Real , b:: Real ) where {β}
350
366
CoordI = zeros (8 n- 4 )
351
367
CoordJ = zeros (8 n- 4 )
352
368
Values = zeros (8 n- 4 )
353
369
354
- c, s, cp, sp = SampleCSValues (n, a, b, d . beta )
370
+ c, s, cp, sp = SampleCSValues (n, a, b, β )
355
371
356
372
# Diagonals of each block
357
373
for i= 1 : n
@@ -392,9 +408,9 @@ function sprand(d::GaussianJacobi, n::Integer, a::Real, b::Real)
392
408
end
393
409
394
410
# Return n eigenvalues distributed according to the Jacobi ensemble
395
- function eigvalrand (d:: GaussianJacobi , n:: Integer )
411
+ function eigvalrand (d:: GaussianJacobi{β} , n:: Integer ) where {β}
396
412
# Generate just the upper left quadrant of the matrix
397
- c, s, cp, sp = SampleCSValues (n, d. a, d. b, d . beta )
413
+ c, s, cp, sp = SampleCSValues (n, d. a, d. b, β )
398
414
dv = [i== 1 ? c[n] : c[n+ 1 - i] * sp[n+ 1 - i] for i= 1 : n]
399
415
ev = [- s[n+ 1 - i]* cp[n- i] for i= 1 : n- 1 ]
400
416
@@ -404,28 +420,28 @@ function eigvalrand(d::GaussianJacobi, n::Integer)
404
420
end
405
421
406
422
# TODO Check m and ns
407
- function eigvaljpdf (d:: GaussianJacobi , lambda:: Vector{Eigenvalue} ) where {Eigenvalue<: Number }
423
+ function eigvaljpdf (d:: GaussianJacobi{β} , lambda:: Vector{Eigenvalue} ) where {β, Eigenvalue<: Number }
408
424
m = length (lambda)
409
425
# Jacobi parameters
410
426
a1, a2 = d. a, d. b
411
- p = 1.0 + d . beta * (m- 1 )/ 2.0
427
+ p = 1.0 + β * (m- 1 )/ 2.0
412
428
# Calculate normalization constant
413
429
c = 1.0
414
430
for j= 1 : m
415
- z1 = (a1 - beta * (m- j)/ 2.0 )
431
+ z1 = (a1 - β * (m- j)/ 2.0 )
416
432
if z1 < 0 && (int (z1) - z1) < eps ()
417
433
return 0.0 # Pole of gamma function, there is no density here no matter what
418
434
end
419
- z2 = (a2 - beta * (m- j)/ 2.0 )
435
+ z2 = (a2 - β * (m- j)/ 2.0 )
420
436
if z2 < 0 && (int (z2) - z2) < eps ()
421
437
return 0.0 # Pole of gamma function, there is no density here no matter what
422
438
end
423
- c *= gamma (1 + beta / 2 )* gamma (a1+ a2- beta * (m- j)/ 2 )
424
- c /= gamma (1 + beta * j/ 2 )* gamma (z1)* gamma (z2)
439
+ c *= gamma (1 + β / 2 )* gamma (a1+ a2- β * (m- j)/ 2 )
440
+ c /= gamma (1 + β * j/ 2 )* gamma (z1)* gamma (z2)
425
441
end
426
442
427
443
Prod = prod (lambda.^ (a1- p))* prod ((1 - lambda). ^ (a2- p)) # Calculate Laguerre product term
428
444
Energy = sum (lambda/ 2 ) # Calculate argument of exponential
429
445
430
- return c * VandermondeDeterminant (lambda, beta ) * Prod * exp (- Energy)
446
+ return c * VandermondeDeterminant (lambda, β ) * Prod * exp (- Energy)
431
447
end
0 commit comments