@@ -69,31 +69,32 @@ is_right_isometric(A; kwargs...) = is_left_isometric(A'; kwargs...)
6969Test whether a linear map is Hermitian, i.e. `A = A'`.
7070The `isapprox_kwargs` can be used to control the tolerances of the equality.
7171"""
72- function ishermitian (A; atol:: Real = 0 , rtol:: Real = 0 , norm = LinearAlgebra . norm, kwargs... )
72+ function ishermitian (A; atol:: Real = 0 , rtol:: Real = 0 , kwargs... )
7373 if iszero (atol) && iszero (rtol)
7474 return ishermitian_exact (A; kwargs... )
7575 else
76- return 2 * norm ( project_antihermitian ( A; kwargs ... )) ≤ max ( atol, rtol * norm (A) )
76+ return ishermitian_approx ( A; atol, rtol, kwargs ... )
7777 end
7878end
79- function ishermitian_exact (A)
80- return A == A'
81- end
82- function ishermitian_exact (A :: StridedMatrix ; kwargs... )
83- return strided_ishermitian_exact (A, Val ( false ) ; kwargs... )
79+
80+ ishermitian_exact (A) = A == A'
81+ ishermitian_exact (A :: StridedMatrix ; kwargs ... ) = strided_ishermitian_exact (A, Val ( false ); kwargs ... )
82+ function ishermitian_approx (A; atol, rtol, kwargs... )
83+ return norm ( project_antihermitian (A ; kwargs... )) ≤ max (atol, rtol * norm (A) )
8484end
85+ ishermitian_approx (A:: StridedMatrix ; kwargs... ) = strided_ishermitian_approx (A, Val (false ); kwargs... )
8586
8687"""
8788 isantihermitian(A; isapprox_kwargs...)
8889
8990Test whether a linear map is anti-Hermitian, i.e. `A = -A'`.
9091The `isapprox_kwargs` can be used to control the tolerances of the equality.
9192"""
92- function isantihermitian (A; atol:: Real = 0 , rtol:: Real = 0 , norm = LinearAlgebra . norm, kwargs... )
93+ function isantihermitian (A; atol:: Real = 0 , rtol:: Real = 0 , kwargs... )
9394 if iszero (atol) && iszero (rtol)
9495 return isantihermitian_exact (A; kwargs... )
9596 else
96- return 2 * norm ( project_hermitian ( A; kwargs ... )) ≤ max ( atol, rtol * norm (A) )
97+ return isantihermitian_approx ( A; atol, rtol, kwargs ... )
9798 end
9899end
99100function isantihermitian_exact (A)
102103function isantihermitian_exact (A:: StridedMatrix ; kwargs... )
103104 return strided_ishermitian_exact (A, Val (true ); kwargs... )
104105end
106+ function isantihermitian_approx (A; atol, rtol, kwargs... )
107+ return norm (project_hermitian (A; kwargs... )) ≤ max (atol, rtol * norm (A))
108+ end
109+ isantihermitian_approx (A:: StridedMatrix ; kwargs... ) = strided_ishermitian_approx (A, Val (true ); kwargs... )
105110
106111# blocked implementation of exact checks for strided matrices
107112# -----------------------------------------------------------
@@ -139,3 +144,51 @@ function _ishermitian_exact_offdiag(Al, Au, ::Val{anti}) where {anti}
139144 end
140145 return true
141146end
147+
148+
149+ function strided_ishermitian_approx (
150+ A:: AbstractMatrix , anti:: Val ;
151+ blocksize = 32 , atol:: Real = default_hermitian_tol (A), rtol:: Real = 0
152+ )
153+ n = size (A, 1 )
154+ ϵ² = abs2 (zero (eltype (A)))
155+ ϵ²max = oftype (ϵ², rtol > 0 ? max (atol, rtol * norm (A)) : atol)^ 2
156+ for j in 1 : blocksize: n
157+ jb = min (blocksize, n - j + 1 )
158+ ϵ² += _ishermitian_approx_diag (view (A, j: (j + jb - 1 ), j: (j + jb - 1 )), anti)
159+ ϵ² < ϵ²max || return false
160+ for i in 1 : blocksize: (j - 1 )
161+ ib = blocksize
162+ ϵ² += 2 * _ishermitian_approx_offdiag (
163+ view (A, i: (i + ib - 1 ), j: (j + jb - 1 )),
164+ view (A, j: (j + jb - 1 ), i: (i + ib - 1 )),
165+ anti
166+ )
167+ ϵ² < ϵ²max || return false
168+ end
169+ end
170+ return true
171+ end
172+
173+ function _ishermitian_approx_diag (A, :: Val{anti} ) where {anti}
174+ n = size (A, 1 )
175+ ϵ² = abs2 (zero (eltype (A)))
176+ @inbounds for j in 1 : n
177+ @simd for i in 1 : j
178+ val = _project_hermitian (A[i, j], A[j, i], ! anti)
179+ ϵ² += abs2 (val) * (1 + Int (i < j))
180+ end
181+ end
182+ return ϵ²
183+ end
184+ function _ishermitian_approx_offdiag (Al, Au, :: Val{anti} ) where {anti}
185+ m, n = size (Al) # == reverse(size(Al))
186+ ϵ² = abs2 (zero (eltype (Al)))
187+ @inbounds for j in 1 : n
188+ @simd for i in 1 : m
189+ val = _project_hermitian (Al[i, j], Au[j, i], ! anti)
190+ ϵ² += abs2 (val)
191+ end
192+ end
193+ return ϵ²
194+ end
0 commit comments