Skip to content

Commit 3924196

Browse files
committed
add blocked ishermitian
1 parent e22af66 commit 3924196

1 file changed

Lines changed: 54 additions & 41 deletions

File tree

src/common/matrixproperties.jl

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ function isunitary(A; isapprox_kwargs...)
3131
return is_left_isometry(A; isapprox_kwargs...) &&
3232
is_right_isometry(A; isapprox_kwargs...)
3333
end
34+
# TODO: for matrices, isunitary corresponds to is_left_isometry + square.
3435

3536
@doc """
3637
is_left_isometry(A; isapprox_kwargs...) -> Bool
@@ -64,30 +65,18 @@ end
6465
Test whether a linear map is Hermitian, i.e. `A = A'`.
6566
The `isapprox_kwargs` can be used to control the tolerances of the equality.
6667
"""
67-
function ishermitian(A; atol::Real = 0, rtol::Real = 0, kwargs...)
68-
return (atol == rtol == 0) ? (A == A') : isapprox(A, A'; atol, rtol, kwargs...)
69-
end
70-
function ishermitian(A::AbstractMatrix; atol::Real = 0, rtol::Real = 0, norm = LinearAlgebra.norm, kwargs...)
71-
Base.require_one_based_indexing(A)
72-
m, n = size(A)
73-
m == n || return false
74-
if atol == rtol == 0
75-
for j in 1:n
76-
for i in 1:j
77-
A[i, j] == adjoint(A[j, i]) || return false
78-
end
79-
end
80-
elseif norm === LinearAlgebra.norm
81-
atol = max(atol, rtol * norm(A))
82-
for j in 1:n
83-
for i in 1:j
84-
isapprox(A[i, j], adjoint(A[j, i]); atol, abs, kwargs...) || return false
85-
end
86-
end
68+
function ishermitian(A; atol::Real = 0, rtol::Real = 0, norm = LinearAlgebra.norm, kwargs...)
69+
if iszero(atol) && iszero(rtol)
70+
return ishermitian_exact(A; kwargs...)
8771
else
88-
return isapprox(A, A'; atol, rtol, norm, kwargs...)
72+
return 2 * norm(project_antihermitian(A; kwargs...)) max(atol, rtol * norm(A))
8973
end
90-
return true
74+
end
75+
function ishermitian_exact(A)
76+
return A == A'
77+
end
78+
function ishermitian_exact(A::AbstractMatrix; kwargs...)
79+
return _ishermitian_exact(A, Val(false); kwargs...)
9180
end
9281

9382
"""
@@ -96,28 +85,52 @@ end
9685
Test whether a linear map is anti-Hermitian, i.e. `A = -A'`.
9786
The `isapprox_kwargs` can be used to control the tolerances of the equality.
9887
"""
99-
function isantihermitian(A; atol::Real = 0, rtol::Real = 0, kwargs...)
100-
return (atol == 0 & rtol == 0) ? (A == -A') : isapprox(A, -A'; atol, rtol, kwargs...)
88+
function isantihermitian(A; atol::Real = 0, rtol::Real = 0, norm = LinearAlgebra.norm, kwargs...)
89+
if iszero(atol) && iszero(rtol)
90+
return isantihermitian_exact(A; kwargs...)
91+
else
92+
return 2 * norm(project_hermitian(A; kwargs...)) max(atol, rtol * norm(A))
93+
end
94+
end
95+
function isantihermitian_exact(A)
96+
return A == -A'
97+
end
98+
function isantihermitian_exact(A::AbstractMatrix; kwargs...)
99+
return _ishermitian_exact(A, Val(true); kwargs...)
101100
end
102-
function isantihermitian(A::AbstractMatrix; atol::Real = 0, rtol::Real = 0, norm = LinearAlgebra.norm, kwargs...)
103-
Base.require_one_based_indexing(A)
104-
m, n = size(A)
105-
m == n || return false
106-
if atol == rtol == 0
107-
@inbounds for j in 1:n
108-
for i in 1:j
109-
A[i, j] == -adjoint(A[j, i]) || return false
110-
end
101+
102+
# block implementation of exact checks
103+
function _ishermitian_exact(A::AbstractMatrix, anti::Val; blocksize = 32)
104+
n = size(A, 1)
105+
for j in 1:blocksize:n
106+
jb = min(blocksize, n - j + 1)
107+
_ishermitian_exact_diag(view(A, j:(j + jb - 1), j:(j + jb - 1)), anti) || return false
108+
for i in 1:blocksize:(j - 1)
109+
ib = blocksize
110+
_ishermitian_exact_offdiag(
111+
view(A, i:(i + ib - 1), j:(j + jb - 1)),
112+
view(A, j:(j + jb - 1), i:(i + ib - 1)),
113+
anti
114+
) || return false
111115
end
112-
elseif norm === LinearAlgebra.norm
113-
atol = max(atol, rtol * norm(A))
114-
@inbounds for j in 1:n
115-
for i in 1:j
116-
isapprox(A[i, j], -adjoint(A[j, i]); atol, abs, kwargs...) || return false
117-
end
116+
end
117+
return true
118+
end
119+
function _ishermitian_exact_diag(A, ::Val{anti}) where {anti}
120+
n = size(A, 1)
121+
@inbounds for j in 1:n
122+
@simd for i in 1:j
123+
A[i, j] == (anti ? -adjoint(A[j, i]) : adjoint(A[j, i])) || return false
124+
end
125+
end
126+
return true
127+
end
128+
function _ishermitian_exact_offdiag(Al, Au, ::Val{anti}) where {anti}
129+
m, n = size(Al) # == reverse(size(Al))
130+
@inbounds for j in 1:n
131+
@simd for i in 1:m
132+
Al[i, j] == (anti ? -adjoint(Au[j, i]) : adjoint(Au[j, i])) || return false
118133
end
119-
else
120-
return isapprox(A, -A'; atol, rtol, norm, kwargs...)
121134
end
122135
return true
123136
end

0 commit comments

Comments
 (0)