@@ -224,11 +224,15 @@ const RealHermSymSymTri{T<:Real} = Union{RealHermSym{T}, SymTridiagonal{T}}
224
224
const RealHermSymComplexHerm{T<: Real ,S} = Union{Hermitian{T,S}, Symmetric{T,S}, Hermitian{Complex{T},S}}
225
225
const RealHermSymComplexSym{T<: Real ,S} = Union{Hermitian{T,S}, Symmetric{T,S}, Symmetric{Complex{T},S}}
226
226
const 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 }
228
228
229
229
wrappertype (:: Union{Symmetric, SymTridiagonal} ) = Symmetric
230
230
wrappertype (:: Hermitian ) = Hermitian
231
231
232
+ nonhermitianwrappertype (:: SymSymTri{<:Real} ) = Symmetric
233
+ nonhermitianwrappertype (:: Hermitian{<:Real} ) = Symmetric
234
+ nonhermitianwrappertype (:: Hermitian ) = identity
235
+
232
236
size (A:: HermOrSym ) = size (A. data)
233
237
axes (A:: HermOrSym ) = axes (A. data)
234
238
@inline function Base. isassigned (A:: HermOrSym , i:: Int , j:: Int )
@@ -834,119 +838,74 @@ end
834
838
^ (A:: Symmetric{<:Complex} , p:: Integer ) = sympow (A, p)
835
839
^ (A:: SymTridiagonal{<:Real} , p:: Integer ) = sympow (A, p)
836
840
^ (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 )
862
843
if p < 0
863
844
retmat = Base. power_by_squaring (inv (A), - p)
864
845
else
865
846
retmat = Base. power_by_squaring (A, p)
866
847
end
867
- return Hermitian (retmat)
848
+ return wrappertype (A) (retmat)
868
849
end
869
- function ^ (A:: Hermitian{T} , p:: Real ) where T
850
+ function ^ (A:: SelfAdjoint , p:: Real )
870
851
isinteger (p) && return integerpow (A, p)
871
852
F = eigen (A)
872
853
if all (λ -> λ ≥ 0 , F. values)
873
854
retmat = (F. vectors * Diagonal ((F. values). ^ p)) * F. vectors'
874
- return Hermitian (retmat)
855
+ return wrappertype (A) (retmat)
875
856
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)
882
859
end
883
860
end
861
+ function ^ (A:: SymSymTri{<:Complex} , p:: Real )
862
+ isinteger (p) && return integerpow (A, p)
863
+ return Symmetric (schurpow (A, p))
864
+ end
884
865
885
866
for func in (:exp , :cos , :sin , :tan , :cosh , :sinh , :tanh , :atan , :asinh , :atanh , :cbrt )
886
867
@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 )
892
869
F = eigen (A)
893
870
retmat = (F. vectors * Diagonal (($ func). (F. values))) * F. vectors'
894
- return Hermitian (retmat)
871
+ return wrappertype (A) (retmat)
895
872
end
896
873
end
897
874
end
898
875
899
- function cis (A:: RealHermSymSymTri )
876
+ function cis (A:: SelfAdjoint )
900
877
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)
902
880
end
903
- function cis (A:: Hermitian{<:Complex} )
904
- F = eigen (A)
905
- return F. vectors .* cis .(F. values' ) * F. vectors'
906
- end
907
-
908
881
909
882
for func in (:acos , :asin )
910
883
@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 )
920
885
F = eigen (A)
921
886
if all (λ -> - 1 ≤ λ ≤ 1 , F. values)
922
887
retmat = (F. vectors * Diagonal (($ func). (F. values))) * F. vectors'
923
- return Hermitian (retmat)
888
+ return wrappertype (A) (retmat)
924
889
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)
926
892
end
927
893
end
928
894
end
929
895
end
930
896
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 )
940
898
F = eigen (A)
941
899
if all (λ -> λ ≥ 1 , F. values)
942
900
retmat = (F. vectors * Diagonal (acosh .(F. values))) * F. vectors'
943
- return Hermitian (retmat)
901
+ return wrappertype (A) (retmat)
944
902
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)
946
905
end
947
906
end
948
907
949
- function sincos (A:: RealHermSymSymTri )
908
+ function sincos (A:: SelfAdjoint )
950
909
n = checksquare (A)
951
910
F = eigen (A)
952
911
T = float (eltype (F. values))
@@ -956,49 +915,28 @@ function sincos(A::RealHermSymSymTri)
956
915
end
957
916
return wrappertype (A)((F. vectors * S) * F. vectors' ), wrappertype (A)((F. vectors * C) * F. vectors' )
958
917
end
959
- function sincos (A :: Hermitian{<:Complex} )
960
- n = checksquare (A )
918
+
919
+ function log (A :: SelfAdjoint )
961
920
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)
971
927
end
972
- return Hermitian (retmatS), Hermitian (retmatC)
973
928
end
974
929
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)
1002
940
end
1003
941
end
1004
942
0 commit comments