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