@@ -31,6 +31,7 @@ function isunitary(A; isapprox_kwargs...)
3131 return is_left_isometry (A; isapprox_kwargs... ) &&
3232 is_right_isometry (A; isapprox_kwargs... )
3333end
34+ # TODO : for matrices, isunitary corresponds to is_left_isometry + square.
3435
3536@doc """
3637 is_left_isometry(A; isapprox_kwargs...) -> Bool
6465Test whether a linear map is Hermitian, i.e. `A = A'`.
6566The `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... )
9180end
9281
9382"""
9685Test whether a linear map is anti-Hermitian, i.e. `A = -A'`.
9786The `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... )
101100end
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
123136end
0 commit comments