@@ -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