@@ -224,15 +224,11 @@ const RealHermSymSymTri{T<:Real} = Union{RealHermSym{T}, SymTridiagonal{T}}
224224const RealHermSymComplexHerm{T<: Real ,S} = Union{Hermitian{T,S}, Symmetric{T,S}, Hermitian{Complex{T},S}}
225225const RealHermSymComplexSym{T<: Real ,S} = Union{Hermitian{T,S}, Symmetric{T,S}, Symmetric{Complex{T},S}}
226226const RealHermSymSymTriComplexHerm{T<: Real } = Union{RealHermSymComplexSym{T}, SymTridiagonal{T}}
227- const SelfAdjoint = Union{SymTridiagonal {<: Real }, Symmetric {<: Real }, Hermitian }
227+ const SelfAdjoint = Union{Symmetric {<: Real }, Hermitian {<: Number } }
228228
229229wrappertype (:: Union{Symmetric, SymTridiagonal} ) = Symmetric
230230wrappertype (:: Hermitian ) = Hermitian
231231
232- nonhermitianwrappertype (:: SymSymTri{<:Real} ) = Symmetric
233- nonhermitianwrappertype (:: Hermitian{<:Real} ) = Symmetric
234- nonhermitianwrappertype (:: Hermitian ) = identity
235-
236232size (A:: HermOrSym ) = size (A. data)
237233axes (A:: HermOrSym ) = axes (A. data)
238234@inline function Base. isassigned (A:: HermOrSym , i:: Int , j:: Int )
@@ -838,74 +834,119 @@ end
838834^ (A:: Symmetric{<:Complex} , p:: Integer ) = sympow (A, p)
839835^ (A:: SymTridiagonal{<:Real} , p:: Integer ) = sympow (A, p)
840836^ (A:: SymTridiagonal{<:Complex} , p:: Integer ) = sympow (A, p)
841- ^ (A:: Hermitian , p:: Integer ) = sympow (A, p)
842- function sympow (A, p:: Integer )
837+ function sympow (A:: SymSymTri , p:: Integer )
838+ if p < 0
839+ return Symmetric (Base. power_by_squaring (inv (A), - p))
840+ else
841+ return Symmetric (Base. power_by_squaring (A, p))
842+ end
843+ end
844+ for hermtype in (:Symmetric , :SymTridiagonal )
845+ @eval begin
846+ function ^ (A:: $hermtype{<:Real} , p:: Real )
847+ isinteger (p) && return integerpow (A, p)
848+ F = eigen (A)
849+ if all (λ -> λ ≥ 0 , F. values)
850+ return Symmetric ((F. vectors * Diagonal ((F. values). ^ p)) * F. vectors' )
851+ else
852+ return Symmetric ((F. vectors * Diagonal (complex .(F. values).^ p)) * F. vectors' )
853+ end
854+ end
855+ function ^ (A:: $hermtype{<:Complex} , p:: Real )
856+ isinteger (p) && return integerpow (A, p)
857+ return Symmetric (schurpow (A, p))
858+ end
859+ end
860+ end
861+ function ^ (A:: Hermitian , p:: Integer )
843862 if p < 0
844863 retmat = Base. power_by_squaring (inv (A), - p)
845864 else
846865 retmat = Base. power_by_squaring (A, p)
847866 end
848- return wrappertype (A) (retmat)
867+ return Hermitian (retmat)
849868end
850- function ^ (A:: SelfAdjoint , p:: Real )
869+ function ^ (A:: Hermitian{T} , p:: Real ) where T
851870 isinteger (p) && return integerpow (A, p)
852871 F = eigen (A)
853872 if all (λ -> λ ≥ 0 , F. values)
854873 retmat = (F. vectors * Diagonal ((F. values). ^ p)) * F. vectors'
855- return wrappertype (A) (retmat)
874+ return Hermitian (retmat)
856875 else
857- retmat = (F. vectors * Diagonal (complex .(F. values).^ p)) * F. vectors'
858- return nonhermitianwrappertype (A)(retmat)
876+ retmat = (F. vectors * Diagonal ((complex .(F. values).^ p))) * F. vectors'
877+ if T <: Real
878+ return Symmetric (retmat)
879+ else
880+ return retmat
881+ end
859882 end
860883end
861- function ^ (A:: SymSymTri{<:Complex} , p:: Real )
862- isinteger (p) && return integerpow (A, p)
863- return Symmetric (schurpow (A, p))
864- end
865884
866885for func in (:exp , :cos , :sin , :tan , :cosh , :sinh , :tanh , :atan , :asinh , :atanh , :cbrt )
867886 @eval begin
868- function ($ func)(A:: SelfAdjoint )
887+ function ($ func)(A:: RealHermSymSymTri )
888+ F = eigen (A)
889+ return wrappertype (A)((F. vectors * Diagonal (($ func). (F. values))) * F. vectors' )
890+ end
891+ function ($ func)(A:: Hermitian{<:Complex} )
869892 F = eigen (A)
870893 retmat = (F. vectors * Diagonal (($ func). (F. values))) * F. vectors'
871- return wrappertype (A) (retmat)
894+ return Hermitian (retmat)
872895 end
873896 end
874897end
875898
876- function cis (A:: SelfAdjoint )
899+ function cis (A:: RealHermSymSymTri )
877900 F = eigen (A)
878- retmat = F. vectors .* cis .(F. values' ) * F. vectors'
879- return nonhermitianwrappertype (A)(retmat)
901+ return Symmetric (F. vectors .* cis .(F. values' ) * F. vectors' )
880902end
903+ function cis (A:: Hermitian{<:Complex} )
904+ F = eigen (A)
905+ return F. vectors .* cis .(F. values' ) * F. vectors'
906+ end
907+
881908
882909for func in (:acos , :asin )
883910 @eval begin
884- function ($ func)(A:: SelfAdjoint )
911+ function ($ func)(A:: RealHermSymSymTri )
912+ F = eigen (A)
913+ if all (λ -> - 1 ≤ λ ≤ 1 , F. values)
914+ return wrappertype (A)((F. vectors * Diagonal (($ func). (F. values))) * F. vectors' )
915+ else
916+ return Symmetric ((F. vectors * Diagonal (($ func). (complex .(F. values)))) * F. vectors' )
917+ end
918+ end
919+ function ($ func)(A:: Hermitian{<:Complex} )
885920 F = eigen (A)
886921 if all (λ -> - 1 ≤ λ ≤ 1 , F. values)
887922 retmat = (F. vectors * Diagonal (($ func). (F. values))) * F. vectors'
888- return wrappertype (A) (retmat)
923+ return Hermitian (retmat)
889924 else
890- retmat = (F. vectors * Diagonal (($ func). (complex .(F. values)))) * F. vectors'
891- return nonhermitianwrappertype (A)(retmat)
925+ return (F. vectors * Diagonal (($ func). (complex .(F. values)))) * F. vectors'
892926 end
893927 end
894928 end
895929end
896930
897- function acosh (A:: SelfAdjoint )
931+ function acosh (A:: RealHermSymSymTri )
932+ F = eigen (A)
933+ if all (λ -> λ ≥ 1 , F. values)
934+ return wrappertype (A)((F. vectors * Diagonal (acosh .(F. values))) * F. vectors' )
935+ else
936+ return Symmetric ((F. vectors * Diagonal (acosh .(complex .(F. values)))) * F. vectors' )
937+ end
938+ end
939+ function acosh (A:: Hermitian{<:Complex} )
898940 F = eigen (A)
899941 if all (λ -> λ ≥ 1 , F. values)
900942 retmat = (F. vectors * Diagonal (acosh .(F. values))) * F. vectors'
901- return wrappertype (A) (retmat)
943+ return Hermitian (retmat)
902944 else
903- retmat = (F. vectors * Diagonal (acosh .(complex .(F. values)))) * F. vectors'
904- return nonhermitianwrappertype (A)(retmat)
945+ return (F. vectors * Diagonal (acosh .(complex .(F. values)))) * F. vectors'
905946 end
906947end
907948
908- function sincos (A:: SelfAdjoint )
949+ function sincos (A:: RealHermSymSymTri )
909950 n = checksquare (A)
910951 F = eigen (A)
911952 T = float (eltype (F. values))
@@ -915,28 +956,49 @@ function sincos(A::SelfAdjoint)
915956 end
916957 return wrappertype (A)((F. vectors * S) * F. vectors' ), wrappertype (A)((F. vectors * C) * F. vectors' )
917958end
918-
919- function log (A :: SelfAdjoint )
959+ function sincos (A :: Hermitian{<:Complex} )
960+ n = checksquare (A )
920961 F = eigen (A)
921- if all (λ -> λ ≥ 0 , F. values)
922- retmat = (F. vectors * Diagonal (log .(F. values))) * F. vectors'
923- return wrappertype (A)(retmat)
924- else
925- retmat = (F. vectors * Diagonal (log .(complex .(F. values)))) * F. vectors'
926- return nonhermitianwrappertype (A)(retmat)
962+ T = float (eltype (F. values))
963+ S, C = Diagonal (similar (A, T, (n,))), Diagonal (similar (A, T, (n,)))
964+ for i in eachindex (S. diag, C. diag, F. values)
965+ S. diag[i], C. diag[i] = sincos (F. values[i])
966+ end
967+ retmatS, retmatC = (F. vectors * S) * F. vectors' , (F. vectors * C) * F. vectors'
968+ for i in diagind (retmatS, IndexStyle (retmatS))
969+ retmatS[i] = real (retmatS[i])
970+ retmatC[i] = real (retmatC[i])
927971 end
972+ return Hermitian (retmatS), Hermitian (retmatC)
928973end
929974
930- # sqrt has rtol kwarg to handle matrices that are semidefinite up to roundoff errors
931- function sqrt (A:: SelfAdjoint ; rtol = eps (real (float (eltype (A)))) * size (A, 1 ))
932- F = eigen (A)
933- λ₀ = - maximum (abs, F. values) * rtol # treat λ ≥ λ₀ as "zero" eigenvalues up to roundoff
934- if all (λ -> λ ≥ λ₀, F. values)
935- retmat = (F. vectors * Diagonal (sqrt .(max .(0 , F. values)))) * F. vectors'
936- return wrappertype (A)(retmat)
937- else
938- retmat = (F. vectors * Diagonal (sqrt .(complex .(F. values)))) * F. vectors'
939- return nonhermitianwrappertype (A)(retmat)
975+
976+ for func in (:log , :sqrt )
977+ # sqrt has rtol arg to handle matrices that are semidefinite up to roundoff errors
978+ rtolarg = func === :sqrt ? Any[Expr (:kw , :(rtol:: Real ), :(eps (real (float (one (T))))* size (A,1 )))] : Any[]
979+ rtolval = func === :sqrt ? :(- maximum (abs, F. values) * rtol) : 0
980+ @eval begin
981+ function ($ func)(A:: RealHermSymSymTri{T} ; $ (rtolarg... )) where {T<: Real }
982+ F = eigen (A)
983+ λ₀ = $ rtolval # treat λ ≥ λ₀ as "zero" eigenvalues up to roundoff
984+ if all (λ -> λ ≥ λ₀, F. values)
985+ return wrappertype (A)((F. vectors * Diagonal (($ func). (max .(0 , F. values)))) * F. vectors' )
986+ else
987+ return Symmetric ((F. vectors * Diagonal (($ func). (complex .(F. values)))) * F. vectors' )
988+ end
989+ end
990+ function ($ func)(A:: Hermitian{T} ; $ (rtolarg... )) where {T<: Complex }
991+ n = checksquare (A)
992+ F = eigen (A)
993+ λ₀ = $ rtolval # treat λ ≥ λ₀ as "zero" eigenvalues up to roundoff
994+ if all (λ -> λ ≥ λ₀, F. values)
995+ retmat = (F. vectors * Diagonal (($ func). (max .(0 , F. values)))) * F. vectors'
996+ return Hermitian (retmat)
997+ else
998+ retmat = (F. vectors * Diagonal (($ func). (complex .(F. values)))) * F. vectors'
999+ return retmat
1000+ end
1001+ end
9401002 end
9411003end
9421004
0 commit comments