@@ -24,11 +24,12 @@ export GaussianHermite, GaussianLaguerre, GaussianJacobi,
2424# ####################
2525
2626"""
27- GaussianHermite(β::Int) <: ContinuousMatrixDistribution
27+ GaussianHermite{β} <: ContinuousMatrixDistribution
28+ GaussianHermite(β::Real) -> GaussianHermite{β}()
2829
2930Represents a Gaussian Hermite ensemble with Dyson index `β`.
3031
31- `Wigner(β) ` is a synonym.
32+ `Wigner{β} ` is a synonym.
3233
3334## Examples
3435
@@ -41,15 +42,15 @@ julia> rand(Wigner(2), 3)
4142```
4243"""
4344struct GaussianHermite{β} <: ContinuousMatrixDistribution end
44- GaussianHermite (β) = GaussianHermite {β} ()
45+ GaussianHermite (β:: Real ) = GaussianHermite {β} ()
4546
4647"""
4748Synonym for GaussianHermite{β}
4849"""
4950const Wigner{β} = GaussianHermite{β}
5051
5152"""
52- rand(d::Wigner, n::Int)
53+ rand(d::Wigner{β} , n::Int)
5354
5455Generates an `n × n` matrix randomly sampled from the Gaussian-Hermite ensemble (also known as the Wigner ensemble).
5556
@@ -64,16 +65,24 @@ function rand(d::Wigner{1}, n::Int)
6465end
6566
6667function rand (d:: Wigner{2} , n:: Int )
67- A = randn (n, n) + im * randn ( n, n)
68+ A = randn (ComplexF64, n, n)
6869 normalization = √ (4 * n)
6970 return Hermitian ((A + A' ) / normalization)
7071end
7172
7273function rand (d:: Wigner{4} , n:: Int )
7374 # 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
7786 normalization = √ (8 * n)
7887 return Hermitian ((A + A' ) / normalization)
7988end
@@ -90,7 +99,7 @@ function rand(d::Wigner{β}, dims::Int...) where {β}
9099end
91100
92101"""
93- tridand(d::Wigner, n::Int)
102+ tridand(d::Wigner{β} , n::Int)
94103
95104Generates an `n × n` symmetric tridiagonal matrix from the Gaussian-Hermite ensemble (also known as the Wigner ensemble).
96105
@@ -158,15 +167,15 @@ end
158167# ####################
159168
160169"""
161- GaussianLaguerre(β::Real, a::Real)` <: ContinuousMatrixDistribution
170+ GaussianLaguerre{β}(a::Real)` <: ContinuousMatrixDistribution
171+ GaussianLaguerre(β::Real, a::Real) -> GaussianLaguerre{β}(a)
162172
163173Represents a Gaussian-Laguerre ensemble with Dyson index `β` and `a` parameter
164174used to control the density of eigenvalues near `λ = 0`.
165175
166- `Wishart(β, a)` is a synonym.
176+ `Wishart{β}( a)` is a synonym.
167177
168178## Fields
169- - `beta`: Dyson index
170179- `a`: Parameter used for weighting the joint probability density function of the ensemble
171180
172181## Examples
@@ -186,32 +195,41 @@ julia> rand(GaussianLaguerre(4, 8), 2)
186195## References:
187196- Edelman and Rao, 2005
188197"""
189- mutable struct GaussianLaguerre <: ContinuousMatrixDistribution
190- beta:: Real
198+ struct GaussianLaguerre{β} <: ContinuousMatrixDistribution
191199 a:: Real
192200end
193- const Wishart = GaussianLaguerre
201+ GaussianLaguerre (β:: Real , a:: Real ) = GaussianLaguerre {β} (a:: Real )
202+ const Wishart{β} = GaussianLaguerre{β}
194203
195204# TODO Check - the eigenvalue distribution looks funky
196205# TODO The appropriate matrix size should be calculated from a and one matrix dimension
197206"""
198- rand(d::GaussianLaguerre, n::Int)
207+ rand(d::GaussianLaguerre{β} , n::Int)
199208
200209Generate a random matrix sampled from the Gaussian Laguerre ensemble (also known as the Wishart ensemble)
201210with parameters defined in `d`.
202211
203212The Dyson index `β` is restricted to `β = 1,2` (`n × n` matrix) or `4` (`2n × 2n` block matrix representation),
204213for real, complex, and quaternionic fields, respectively.
205214"""
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)
211219 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)
213226 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)
215233 # employs 2x2 matrix representation of quaternions
216234 X = randn (ComplexF64, m, n)
217235 Y = randn (ComplexF64, m, n)
@@ -224,26 +242,24 @@ function rand(d::GaussianLaguerre, n::Int)
224242 A[i, j+ n] = y
225243 A[i+ m, j+ n] = conj (x)
226244 end
227- else
228- error (" beta = $(beta) is not implemented" )
229- end
230- return (A' * A) / n
245+ return (A' * A) / n
231246end
247+ rand (d:: GaussianLaguerre{β} , n:: Int ) where {β} = throw (ArgumentError (" beta = $(β) is not implemented" ))
232248
233249"""
234- bidrand(d::GaussianLaguerre, n::Int)
250+ bidrand(d::GaussianLaguerre{β} , n::Int)
235251
236252Generate an `n × n` bidiagonal matrix sampled from the Gaussian Laguerre ensemble (also known as the Wishart ensemble).
237253"""
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) )" )
241257 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 )
243259end
244260
245261"""
246- tridrand(d::GaussianLaguerre, n::Int)
262+ tridrand(d::GaussianLaguerre{β} , n::Int)
247263
248264Generate an `n × n` tridiagonal matrix sampled from the Gaussian Laguerre ensemble (also known as the Wishart ensemble).
249265"""
@@ -257,25 +273,25 @@ end
257273eigvalrand (d:: GaussianLaguerre , m:: Integer ) = eigvals (tridrand (d, m))
258274
259275# 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 }
261277 m = length (lambda)
262278 # Laguerre parameters
263- p = 0.5 * d . beta * (m- 1 ) + 1.0
279+ p = 0.5 * β * (m- 1 ) + 1.0
264280 # Calculate normalization constant
265281 c = 2.0 ^- (m* d. a)
266- z = (d. a - d . beta * (m)* 0.5 )
282+ z = (d. a - β * (m)* 0.5 )
267283 for j= 1 : m
268- z += 0.5 * d . beta
284+ z += 0.5 * β
269285 if z < 0 && (int (z) - z) < eps ()
270286 # Pole of gamma function, there is no density here no matter what
271287 return 0.0
272288 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))
274290 end
275291
276- Prod = prod (lambda.^ (a- p)) # Calculate Laguerre product term
292+ Prod = prod (lambda.^ (d . a- p)) # Calculate Laguerre product term
277293 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)
279295end
280296
281297
@@ -285,37 +301,37 @@ end
285301# ##################
286302
287303"""
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)
289306
290307Represents a Gaussian-Jacobi ensemble with Dyson index `β`, while
291308`a`and `b` are parameters used to weight the joint probability density function of the ensemble.
292309
293- `MANOVA(β, a, b)` is a synonym.
310+ `MANOVA{β}( a, b)` is a synonym.
294311
295312## Fields
296- - `beta`: Dyson index
297313- `a`: Parameter used for shaping the joint probability density function near `λ = 0`
298314- `b`: Parameter used for shaping the joint probability density function near `λ = 1`
299315
300316## References:
301317- Edelman and Rao, 2005
302318"""
303- mutable struct GaussianJacobi <: ContinuousMatrixDistribution
304- beta:: Real
319+ struct GaussianJacobi{β} <: ContinuousMatrixDistribution
305320 a:: Real
306321 b:: Real
307322end
308- const MANOVA = GaussianJacobi
323+ GaussianJacobi (β:: Real , a:: Real , b:: Real ) = GaussianJacobi {β} (a, b)
324+ const MANOVA{β} = GaussianJacobi{β}
309325
310326"""
311- rand(d::GaussianJacobi, n::Int)
327+ rand(d::GaussianJacobi{β} , n::Int)
312328
313329Generate an `n × n` random matrix sampled from the Gaussian-Jacobi ensemble (also known as the MANOVA ensemble)
314330with parameters defined in `d`.
315331"""
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 )
319335 return (w1 + w2) \ w1
320336end
321337
@@ -346,12 +362,12 @@ end
346362# and generalized singular value problems", Foundations of Computational Mathematics,
347363# vol. 8 iss. 2 (2008), pp 259-285.
348364# 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 {β}
350366 CoordI = zeros (8 n- 4 )
351367 CoordJ = zeros (8 n- 4 )
352368 Values = zeros (8 n- 4 )
353369
354- c, s, cp, sp = SampleCSValues (n, a, b, d . beta )
370+ c, s, cp, sp = SampleCSValues (n, a, b, β )
355371
356372 # Diagonals of each block
357373 for i= 1 : n
@@ -392,9 +408,9 @@ function sprand(d::GaussianJacobi, n::Integer, a::Real, b::Real)
392408end
393409
394410# Return n eigenvalues distributed according to the Jacobi ensemble
395- function eigvalrand (d:: GaussianJacobi , n:: Integer )
411+ function eigvalrand (d:: GaussianJacobi{β} , n:: Integer ) where {β}
396412 # 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, β )
398414 dv = [i== 1 ? c[n] : c[n+ 1 - i] * sp[n+ 1 - i] for i= 1 : n]
399415 ev = [- s[n+ 1 - i]* cp[n- i] for i= 1 : n- 1 ]
400416
@@ -404,28 +420,28 @@ function eigvalrand(d::GaussianJacobi, n::Integer)
404420end
405421
406422# 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 }
408424 m = length (lambda)
409425 # Jacobi parameters
410426 a1, a2 = d. a, d. b
411- p = 1.0 + d . beta * (m- 1 )/ 2.0
427+ p = 1.0 + β * (m- 1 )/ 2.0
412428 # Calculate normalization constant
413429 c = 1.0
414430 for j= 1 : m
415- z1 = (a1 - beta * (m- j)/ 2.0 )
431+ z1 = (a1 - β * (m- j)/ 2.0 )
416432 if z1 < 0 && (int (z1) - z1) < eps ()
417433 return 0.0 # Pole of gamma function, there is no density here no matter what
418434 end
419- z2 = (a2 - beta * (m- j)/ 2.0 )
435+ z2 = (a2 - β * (m- j)/ 2.0 )
420436 if z2 < 0 && (int (z2) - z2) < eps ()
421437 return 0.0 # Pole of gamma function, there is no density here no matter what
422438 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)
425441 end
426442
427443 Prod = prod (lambda.^ (a1- p))* prod ((1 - lambda). ^ (a2- p)) # Calculate Laguerre product term
428444 Energy = sum (lambda/ 2 ) # Calculate argument of exponential
429445
430- return c * VandermondeDeterminant (lambda, beta ) * Prod * exp (- Energy)
446+ return c * VandermondeDeterminant (lambda, β ) * Prod * exp (- Energy)
431447end
0 commit comments