Skip to content

Commit

Permalink
fix Stewart's algorithm (#80)
Browse files Browse the repository at this point in the history
* fix Stewart's algorithm

* remove extra export

* compatibility fixes for 1.9

* set minimum julia version 1.6

* bump CI version
  • Loading branch information
araujoms authored Jul 23, 2024
1 parent cfd1955 commit abfafc8
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
fail-fast: false
matrix:
version:
- '1.0'
- '1.6'
- '1'
# - 'nightly'
os:
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
FastGaussQuadrature = "0.3, 0.4, 0.5, 1"
GSL = "0.4, 1"
SpecialFunctions = "0.7, 1, 2"
julia = "0.7, 1"
julia = "1.6"
65 changes: 44 additions & 21 deletions src/HaarMeasure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function rand(W::Haar, n::Int, doCorrection::Int=1)
else
error(string("beta = ",beta, " not implemented."))
end
q*diagm(0 => L)
q*Diagonal(L)
elseif doCorrection==2
if beta==1
L=sign.(diag(r))
Expand All @@ -46,7 +46,7 @@ function rand(W::Haar, n::Int, doCorrection::Int=1)
else
error(string("beta = ",beta, " not implemented."))
end
q*diagm(0 => L)
q*Diagonal(L)
end
end

Expand Down Expand Up @@ -81,35 +81,58 @@ for (s, elty) in (("dlarfg_", Float64),
end
end

"""
Stewarts algorithm for n^2 orthogonal random matrix
"""
function Stewart(::Type{Float64}, n)
τ = Array{Float64}(undef, n)
H = randn(n, n)

= pointer(τ)
= pointer(H)
pH = pointer(H, 2)
import Base.size
import LinearAlgebra: lmul!, rmul!, QRPackedQ, Diagonal, Adjoint

for i = 0:n-2
larfg!(n - i, pβ + (n + 1)*8i, pH + (n + 1)*8i, 1, pτ + 8i)
end
LinearAlgebra.QRPackedQ(H,τ)


struct StewartQ{T,S<:AbstractMatrix{T},C<:AbstractVector{T},D<:AbstractVector{T}} <: LinearAlgebra.AbstractQ{T}
factors::S
τ::C
signs::D
end
size(Q::StewartQ, dim::Integer) = size(Q.factors, dim == 2 ? 1 : dim)
size(Q::StewartQ) = (n = size(Q.factors, 1); (n, n))

function Stewart(::Type{ComplexF64}, n)
τ = Array{ComplexF64}(undef, n)
H = complex.(randn(n, n), randn(n,n))
lmul!(A::StewartQ, B::AbstractVecOrMat) = lmul!(QRPackedQ(A.factors,A.τ), lmul!(Diagonal(A.signs), B))
rmul!(A::AbstractVecOrMat, B::StewartQ) = rmul!(rmul!(A, QRPackedQ(B.factors,B.τ)), Diagonal(B.signs))

@static if VERSION v"1.10"
import LinearAlgebra.AdjointQ
lmul!(adjA::AdjointQ{<:Any,<:StewartQ}, B::AbstractVecOrMat) =
lmul!(Diagonal(adjA.Q.signs), lmul!(QRPackedQ(adjA.Q.factors, adjA.Q.τ)', B))
rmul!(A::AbstractVecOrMat, adjB::AdjointQ{<:Any,<:StewartQ}) =
rmul!(rmul!(A, Diagonal(adjB.Q.signs)), QRPackedQ(adjB.Q.factors, adjB.Q.τ)')
else
lmul!(adjA::Adjoint{<:Any,<:StewartQ}, B::AbstractVecOrMat) =
lmul!(Diagonal(adjA.parent.signs), lmul!(QRPackedQ(adjA.parent.factors, adjA.parent.τ)', B))
rmul!(A::AbstractVecOrMat, adjB::Adjoint{<:Any,<:StewartQ}) =
rmul!(rmul!(A, Diagonal(adjB.parent.signs)), QRPackedQ(adjB.parent.factors,adjB.parent.τ)')
end

StewartQ{T}(Q::StewartQ) where {T} = StewartQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ), convert(Vector{T}, Q.signs))
AbstractMatrix{T}(Q::StewartQ{T}) where {T} = Q
AbstractMatrix{T}(Q::StewartQ) where {T} = StewartQ{T}(Q)

"""
Stewart's algorithm for sampling orthogonal/unitary random matrices in time O(n^2)
"""
function Stewart(::Type{T}, n) where {T<:Union{Float64,ComplexF64}}
τ = Array{T}(undef, n)
signs = Vector{T}(undef, n)
H = randn(T, n, n)

= pointer(τ)
= pointer(H)
pH = pointer(H, 2)

for i = 0:n-2
larfg!(n - i, pβ + (n + 1)*16i, pH + (n + 1)*16i, 1, pτ + 16i)
incr = (T <: Real ? 1 : 2)
for i = 0:n-1
larfg!(n - i, pβ + (n + 1)*8*incr*i, pH + (n + 1)*8*incr*i, 1, pτ + 8*incr*i)
signs[i+1] = sign(real(H[i+1, i+1]))
end
LinearAlgebra.QRPackedQ(H,τ)
return StewartQ(H, τ, signs)
end

export randfast
Expand Down
15 changes: 11 additions & 4 deletions test/Haar.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using RandomMatrices
using LinearAlgebra: I, tr
using LinearAlgebra: I, tr, Diagonal, QRPackedQ
using Test

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

for elty in (Float64, ComplexF64)
A = Stewart(elty, N)
@test A'A Matrix{elty}(I, N, N)
for T in (Float64, ComplexF64)
A = Stewart(T, N)
@test A'A Matrix{T}(I, N, N)
A2 = Matrix(A)
@test A2 QRPackedQ(A.factors, A.τ)*Diagonal(A.signs)
C = randn(T, N, N)
@test A*C A2*C
@test C*A C*A2
@test A'*C A2'*C
@test C*A' C*A2'
end

end # testset

2 comments on commit abfafc8

@dlfivefifty
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error while trying to register: Version 0.5.4 already exists

Please sign in to comment.