Skip to content

Commit abfafc8

Browse files
authored
fix Stewart's algorithm (#80)
* fix Stewart's algorithm * remove extra export * compatibility fixes for 1.9 * set minimum julia version 1.6 * bump CI version
1 parent cfd1955 commit abfafc8

File tree

4 files changed

+57
-27
lines changed

4 files changed

+57
-27
lines changed

.github/workflows/CI.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
fail-fast: false
1414
matrix:
1515
version:
16-
- '1.0'
16+
- '1.6'
1717
- '1'
1818
# - 'nightly'
1919
os:

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ Distributions = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25"
1818
FastGaussQuadrature = "0.3, 0.4, 0.5, 1"
1919
GSL = "0.4, 1"
2020
SpecialFunctions = "0.7, 1, 2"
21-
julia = "0.7, 1"
21+
julia = "1.6"

src/HaarMeasure.jl

+44-21
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function rand(W::Haar, n::Int, doCorrection::Int=1)
3636
else
3737
error(string("beta = ",beta, " not implemented."))
3838
end
39-
q*diagm(0 => L)
39+
q*Diagonal(L)
4040
elseif doCorrection==2
4141
if beta==1
4242
L=sign.(diag(r))
@@ -46,7 +46,7 @@ function rand(W::Haar, n::Int, doCorrection::Int=1)
4646
else
4747
error(string("beta = ",beta, " not implemented."))
4848
end
49-
q*diagm(0 => L)
49+
q*Diagonal(L)
5050
end
5151
end
5252

@@ -81,35 +81,58 @@ for (s, elty) in (("dlarfg_", Float64),
8181
end
8282
end
8383

84-
"""
85-
Stewarts algorithm for n^2 orthogonal random matrix
86-
"""
87-
function Stewart(::Type{Float64}, n)
88-
τ = Array{Float64}(undef, n)
89-
H = randn(n, n)
9084

91-
= pointer(τ)
92-
= pointer(H)
93-
pH = pointer(H, 2)
85+
import Base.size
86+
import LinearAlgebra: lmul!, rmul!, QRPackedQ, Diagonal, Adjoint
9487

95-
for i = 0:n-2
96-
larfg!(n - i, pβ + (n + 1)*8i, pH + (n + 1)*8i, 1, pτ + 8i)
97-
end
98-
LinearAlgebra.QRPackedQ(H,τ)
88+
89+
90+
struct StewartQ{T,S<:AbstractMatrix{T},C<:AbstractVector{T},D<:AbstractVector{T}} <: LinearAlgebra.AbstractQ{T}
91+
factors::S
92+
τ::C
93+
signs::D
9994
end
95+
size(Q::StewartQ, dim::Integer) = size(Q.factors, dim == 2 ? 1 : dim)
96+
size(Q::StewartQ) = (n = size(Q.factors, 1); (n, n))
10097

101-
function Stewart(::Type{ComplexF64}, n)
102-
τ = Array{ComplexF64}(undef, n)
103-
H = complex.(randn(n, n), randn(n,n))
98+
lmul!(A::StewartQ, B::AbstractVecOrMat) = lmul!(QRPackedQ(A.factors,A.τ), lmul!(Diagonal(A.signs), B))
99+
rmul!(A::AbstractVecOrMat, B::StewartQ) = rmul!(rmul!(A, QRPackedQ(B.factors,B.τ)), Diagonal(B.signs))
100+
101+
@static if VERSION v"1.10"
102+
import LinearAlgebra.AdjointQ
103+
lmul!(adjA::AdjointQ{<:Any,<:StewartQ}, B::AbstractVecOrMat) =
104+
lmul!(Diagonal(adjA.Q.signs), lmul!(QRPackedQ(adjA.Q.factors, adjA.Q.τ)', B))
105+
rmul!(A::AbstractVecOrMat, adjB::AdjointQ{<:Any,<:StewartQ}) =
106+
rmul!(rmul!(A, Diagonal(adjB.Q.signs)), QRPackedQ(adjB.Q.factors, adjB.Q.τ)')
107+
else
108+
lmul!(adjA::Adjoint{<:Any,<:StewartQ}, B::AbstractVecOrMat) =
109+
lmul!(Diagonal(adjA.parent.signs), lmul!(QRPackedQ(adjA.parent.factors, adjA.parent.τ)', B))
110+
rmul!(A::AbstractVecOrMat, adjB::Adjoint{<:Any,<:StewartQ}) =
111+
rmul!(rmul!(A, Diagonal(adjB.parent.signs)), QRPackedQ(adjB.parent.factors,adjB.parent.τ)')
112+
end
113+
114+
StewartQ{T}(Q::StewartQ) where {T} = StewartQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ), convert(Vector{T}, Q.signs))
115+
AbstractMatrix{T}(Q::StewartQ{T}) where {T} = Q
116+
AbstractMatrix{T}(Q::StewartQ) where {T} = StewartQ{T}(Q)
117+
118+
"""
119+
Stewart's algorithm for sampling orthogonal/unitary random matrices in time O(n^2)
120+
"""
121+
function Stewart(::Type{T}, n) where {T<:Union{Float64,ComplexF64}}
122+
τ = Array{T}(undef, n)
123+
signs = Vector{T}(undef, n)
124+
H = randn(T, n, n)
104125

105126
= pointer(τ)
106127
= pointer(H)
107128
pH = pointer(H, 2)
108129

109-
for i = 0:n-2
110-
larfg!(n - i, pβ + (n + 1)*16i, pH + (n + 1)*16i, 1, pτ + 16i)
130+
incr = (T <: Real ? 1 : 2)
131+
for i = 0:n-1
132+
larfg!(n - i, pβ + (n + 1)*8*incr*i, pH + (n + 1)*8*incr*i, 1, pτ + 8*incr*i)
133+
signs[i+1] = sign(real(H[i+1, i+1]))
111134
end
112-
LinearAlgebra.QRPackedQ(H,τ)
135+
return StewartQ(H, τ, signs)
113136
end
114137

115138
export randfast

test/Haar.jl

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using RandomMatrices
2-
using LinearAlgebra: I, tr
2+
using LinearAlgebra: I, tr, Diagonal, QRPackedQ
33
using Test
44

55
@testset "Haar" begin
@@ -17,9 +17,16 @@ Q=rand(Haar(1), N)
1717
println("Case 3")
1818
@test_broken println("E(A*Q*B*Q'*A*Q*B*Q') = ", eval(expectation(N, :Q, :(A*Q*B*Q'*A*Q*B*Q'))))
1919

20-
for elty in (Float64, ComplexF64)
21-
A = Stewart(elty, N)
22-
@test A'A Matrix{elty}(I, N, N)
20+
for T in (Float64, ComplexF64)
21+
A = Stewart(T, N)
22+
@test A'A Matrix{T}(I, N, N)
23+
A2 = Matrix(A)
24+
@test A2 QRPackedQ(A.factors, A.τ)*Diagonal(A.signs)
25+
C = randn(T, N, N)
26+
@test A*C A2*C
27+
@test C*A C*A2
28+
@test A'*C A2'*C
29+
@test C*A' C*A2'
2330
end
2431

2532
end # testset

0 commit comments

Comments
 (0)