Skip to content

Commit b45d5f4

Browse files
dhoeghdhoegh
authored and
dhoegh
committed
Add the issym/ishermitian based on norm(A - A', Inf)<tol*norm(A,Inf). fix #10298.
1 parent cc889b0 commit b45d5f4

File tree

4 files changed

+63
-6
lines changed

4 files changed

+63
-6
lines changed

base/docs/helpdb.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -7211,9 +7211,9 @@ Given `@osx? a : b`, do `a` on OS X and `b` elsewhere. See documentation for Han
72117211
:@osx
72127212

72137213
doc"""
7214-
ishermitian(A) -> Bool
7214+
ishermitian(A; tol=eps()*norm(A,1)) -> Bool
72157215
7216-
Test whether a matrix is Hermitian.
7216+
Test whether a matrix is Hermitian. The `tol` keyword is only used for matrices of floating point or `Complex{T<:AbstractFloat}` numbers, where it tests `norm(A - A', Inf) < tol*norm(A,Inf)`.
72177217
"""
72187218
ishermitian
72197219

@@ -7345,9 +7345,9 @@ The arguments to a function or constructor are outside the valid domain.
73457345
DomainError
73467346

73477347
doc"""
7348-
issym(A) -> Bool
7348+
issym(A; tol=eps()*norm(A,1)) -> Bool
73497349
7350-
Test whether a matrix is symmetric.
7350+
Test whether a matrix is symmetric. The `tol` keyword is only used for matrices of floating point or `Complex{T<:AbstractFloat}` numbers, where it tests `norm(A - A', Inf) < tol*norm(A,Inf)`.
73517351
"""
73527352
issym
73537353

base/linalg/generic.jl

+33-2
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ condskeel{T<:Integer}(A::AbstractMatrix{T}, p::Real=Inf) = norm(abs(inv(float(A)
350350
condskeel(A::AbstractMatrix, x::AbstractVector, p::Real=Inf) = norm(abs(inv(A))*abs(A)*abs(x), p)
351351
condskeel{T<:Integer}(A::AbstractMatrix{T}, x::AbstractVector, p::Real=Inf) = norm(abs(inv(float(A)))*abs(A)*abs(x), p)
352352

353-
function issym(A::AbstractMatrix)
353+
function _issym(A::AbstractMatrix)
354354
m, n = size(A)
355355
if m != n
356356
return false
@@ -365,7 +365,7 @@ end
365365

366366
issym(x::Number) = true
367367

368-
function ishermitian(A::AbstractMatrix)
368+
function _ishermitian(A::AbstractMatrix)
369369
m, n = size(A)
370370
if m != n
371371
return false
@@ -378,6 +378,37 @@ function ishermitian(A::AbstractMatrix)
378378
return true
379379
end
380380

381+
ishermitian(A::AbstractMatrix) = _ishermitian(A::AbstractMatrix)
382+
issym(A::AbstractMatrix) = _issym(A::AbstractMatrix)
383+
384+
for (f,t) in ((:ishermitian, :ctranspose),(:issym, :transpose))
385+
eval(quote
386+
# ishermitian and issym functions test whether norm(A - A', Inf)<tol*norm(A,Inf) for FloatingPoint matrices
387+
function $f{T<:AbstractFloat}(A::Union{AbstractMatrix{Complex{T}}, AbstractMatrix{T}},tol=eps()*norm(A,1))
388+
# This is performed due to if tol==0. _issym/_ishermitian is a lot faster for exact equality.
389+
tol == 0. && return $(symbol("_", f))(A)
390+
m,n = size(A)
391+
Tnorm = typeof(float(real(zero(T))))
392+
Tsum = promote_type(Float64,Tnorm)
393+
nrm_diff::Tsum = 0
394+
nrm_A::Tsum = 0
395+
@inbounds begin
396+
for i = 1:m
397+
nrmi_diff::Tsum = 0
398+
nrmi_A::Tsum = 0
399+
for j = 1:n
400+
nrmi_diff += abs(A[i,j]-$t(A[j,i]))
401+
nrmi_A += abs(A[i,j])
402+
end
403+
nrm_diff = max(nrm_diff,nrmi_diff)
404+
nrm_A = max(nrm_A,nrmi_A)
405+
end
406+
end
407+
return nrm_diff < tol*nrm_A
408+
end
409+
end)
410+
end
411+
381412
ishermitian(x::Number) = (x == conj(x))
382413

383414
function istriu(A::AbstractMatrix)

base/linalg/symmetric.jl

+4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ function triu(A::Symmetric, k::Integer=0)
105105
end
106106
end
107107

108+
#Test whether a matrix is positive-definite
109+
isposdef!(A::HermOrSym) = isposdef!(A.data, symbol(A.uplo))
110+
isposdef{T}(A::HermOrSym{T}) = (S = typeof(sqrt(one(T))); isposdef!(S == T ? copy(A.data) : convert(AbstractMatrix{S}, A.data), symbol(A.uplo)))
111+
108112
## Matvec
109113
A_mul_B!{T<:BlasFloat,S<:StridedMatrix}(y::StridedVector{T}, A::Symmetric{T,S}, x::StridedVector{T}) = BLAS.symv!(A.uplo, one(T), A.data, x, zero(T), y)
110114
A_mul_B!{T<:BlasComplex,S<:StridedMatrix}(y::StridedVector{T}, A::Hermitian{T,S}, x::StridedVector{T}) = BLAS.hemv!(A.uplo, one(T), A.data, x, zero(T), y)

test/linalg/symmetric.jl

+22
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,25 @@ let A = [1.0+im 2.0; 2.0 0.0]
209209
@test !ishermitian(A)
210210
@test_throws ArgumentError Hermitian(A)
211211
end
212+
213+
# Tests for #10298
214+
for elT in [Float32, Float64]
215+
A1 = ones(elT,10,10)
216+
A = convert(Array{Complex{elT}}, A1)
217+
A[end,1] = Complex{elT}(nextfloat((A[end,1].re)), A[end,1].im)
218+
@test issym(A)
219+
A = A + triu(A1)im - tril(A1)im
220+
@test ishermitian(A)
221+
222+
D=diagm(rand(100))*100
223+
D[end,1] = nextfloat((D[end,1]))
224+
225+
for HOrS in [Hermitian, Symmetric]
226+
@test isposdef(HOrS(D))
227+
@test isposdef!(copy(HOrS(D)))
228+
end
229+
@test ishermitian(D)
230+
@test issym(D)
231+
@test isposdef(D)
232+
end
233+

0 commit comments

Comments
 (0)