@@ -224,11 +224,15 @@ 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{Symmetric {<: Real }, Hermitian {<: Number } }
227+ const SelfAdjoint = Union{SymTridiagonal {<: Real }, Symmetric {<: Real }, Hermitian }
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+
232236size (A:: HermOrSym ) = size (A. data)
233237axes (A:: HermOrSym ) = axes (A. data)
234238@inline function Base. isassigned (A:: HermOrSym , i:: Int , j:: Int )
@@ -834,119 +838,74 @@ end
834838^ (A:: Symmetric{<:Complex} , p:: Integer ) = sympow (A, p)
835839^ (A:: SymTridiagonal{<:Real} , p:: Integer ) = sympow (A, p)
836840^ (A:: SymTridiagonal{<:Complex} , p:: Integer ) = sympow (A, p)
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 )
841+ ^ (A:: Hermitian , p:: Integer ) = sympow (A, p)
842+ function sympow (A, p:: Integer )
862843 if p < 0
863844 retmat = Base. power_by_squaring (inv (A), - p)
864845 else
865846 retmat = Base. power_by_squaring (A, p)
866847 end
867- return Hermitian (retmat)
848+ return wrappertype (A) (retmat)
868849end
869- function ^ (A:: Hermitian{T} , p:: Real ) where T
850+ function ^ (A:: SelfAdjoint , p:: Real )
870851 isinteger (p) && return integerpow (A, p)
871852 F = eigen (A)
872853 if all (λ -> λ ≥ 0 , F. values)
873854 retmat = (F. vectors * Diagonal ((F. values). ^ p)) * F. vectors'
874- return Hermitian (retmat)
855+ return wrappertype (A) (retmat)
875856 else
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
857+ retmat = (F. vectors * Diagonal (complex .(F. values).^ p)) * F. vectors'
858+ return nonhermitianwrappertype (A)(retmat)
882859 end
883860end
861+ function ^ (A:: SymSymTri{<:Complex} , p:: Real )
862+ isinteger (p) && return integerpow (A, p)
863+ return Symmetric (schurpow (A, p))
864+ end
884865
885866for func in (:exp , :cos , :sin , :tan , :cosh , :sinh , :tanh , :atan , :asinh , :atanh , :cbrt )
886867 @eval begin
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} )
868+ function ($ func)(A:: SelfAdjoint )
892869 F = eigen (A)
893870 retmat = (F. vectors * Diagonal (($ func). (F. values))) * F. vectors'
894- return Hermitian (retmat)
871+ return wrappertype (A) (retmat)
895872 end
896873 end
897874end
898875
899- function cis (A:: RealHermSymSymTri )
876+ function cis (A:: SelfAdjoint )
900877 F = eigen (A)
901- return Symmetric (F. vectors .* cis .(F. values' ) * F. vectors' )
878+ retmat = F. vectors .* cis .(F. values' ) * F. vectors'
879+ return nonhermitianwrappertype (A)(retmat)
902880end
903- function cis (A:: Hermitian{<:Complex} )
904- F = eigen (A)
905- return F. vectors .* cis .(F. values' ) * F. vectors'
906- end
907-
908881
909882for func in (:acos , :asin )
910883 @eval begin
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} )
884+ function ($ func)(A:: SelfAdjoint )
920885 F = eigen (A)
921886 if all (λ -> - 1 ≤ λ ≤ 1 , F. values)
922887 retmat = (F. vectors * Diagonal (($ func). (F. values))) * F. vectors'
923- return Hermitian (retmat)
888+ return wrappertype (A) (retmat)
924889 else
925- return (F. vectors * Diagonal (($ func). (complex .(F. values)))) * F. vectors'
890+ retmat = (F. vectors * Diagonal (($ func). (complex .(F. values)))) * F. vectors'
891+ return nonhermitianwrappertype (A)(retmat)
926892 end
927893 end
928894 end
929895end
930896
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} )
897+ function acosh (A:: SelfAdjoint )
940898 F = eigen (A)
941899 if all (λ -> λ ≥ 1 , F. values)
942900 retmat = (F. vectors * Diagonal (acosh .(F. values))) * F. vectors'
943- return Hermitian (retmat)
901+ return wrappertype (A) (retmat)
944902 else
945- return (F. vectors * Diagonal (acosh .(complex .(F. values)))) * F. vectors'
903+ retmat = (F. vectors * Diagonal (acosh .(complex .(F. values)))) * F. vectors'
904+ return nonhermitianwrappertype (A)(retmat)
946905 end
947906end
948907
949- function sincos (A:: RealHermSymSymTri )
908+ function sincos (A:: SelfAdjoint )
950909 n = checksquare (A)
951910 F = eigen (A)
952911 T = float (eltype (F. values))
@@ -956,49 +915,28 @@ function sincos(A::RealHermSymSymTri)
956915 end
957916 return wrappertype (A)((F. vectors * S) * F. vectors' ), wrappertype (A)((F. vectors * C) * F. vectors' )
958917end
959- function sincos (A :: Hermitian{<:Complex} )
960- n = checksquare (A )
918+
919+ function log (A :: SelfAdjoint )
961920 F = eigen (A)
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])
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)
971927 end
972- return Hermitian (retmatS), Hermitian (retmatC)
973928end
974929
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
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)
1002940 end
1003941end
1004942
0 commit comments