diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index f23825940791c..611bb2adb5191 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -107,6 +107,21 @@ end r end +function setindex!(A::Symmetric, v, i::Integer, j::Integer) + i == j || throw(ArgumentError("Cannot set a non-diagonal index in a symmetric matrix")) + setindex!(A.data, v, i, j) +end + +function setindex!(A::Hermitian, v, i::Integer, j::Integer) + if i != j + throw(ArgumentError("Cannot set a non-diagonal index in a Hermitian matrix")) + elseif !isreal(v) + throw(ArgumentError("Cannot set a diagonal entry in a Hermitian matrix to a nonreal value")) + else + setindex!(A.data, v, i, j) + end +end + similar{T}(A::Symmetric, ::Type{T}) = Symmetric(similar(A.data, T)) # Hermitian version can be simplified when check for imaginary part of # diagonal in Hermitian has been removed @@ -133,6 +148,25 @@ convert{T}(::Type{AbstractMatrix{T}}, A::Hermitian) = Hermitian(convert(Abstract copy{T,S}(A::Symmetric{T,S}) = (B = copy(A.data); Symmetric{T,typeof(B)}(B,A.uplo)) copy{T,S}(A::Hermitian{T,S}) = (B = copy(A.data); Hermitian{T,typeof(B)}(B,A.uplo)) + +function copy!(dest::Symmetric, src::Symmetric) + if src.uplo == dest.uplo + copy!(dest.data, src.data) + else + transpose!(dest.data, src.data) + end + return dest +end + +function copy!(dest::Hermitian, src::Hermitian) + if src.uplo == dest.uplo + copy!(dest.data, src.data) + else + ctranspose!(dest.data, src.data) + end + return dest +end + ishermitian(A::Hermitian) = true ishermitian{T<:Real,S}(A::Symmetric{T,S}) = true ishermitian{T<:Complex,S}(A::Symmetric{T,S}) = all(imag(A.data) .== 0) @@ -218,6 +252,13 @@ A_mul_B!{T<:BlasComplex,S<:StridedMatrix}(C::StridedMatrix{T}, A::StridedMatrix{ *(A::HermOrSym, B::HermOrSym) = full(A)*full(B) *(A::StridedMatrix, B::HermOrSym) = A*full(B) +for T in (:Symmetric, :Hermitian), op in (:+, :-, :*, :/) + # Deal with an ambiguous case + @eval ($op)(A::$T, x::Bool) = ($T)(($op)(A.data, x), Symbol(A.uplo)) + S = T == :Hermitian ? :Real : :Number + @eval ($op)(A::$T, x::$S) = ($T)(($op)(A.data, x), Symbol(A.uplo)) +end + bkfact(A::HermOrSym) = bkfact(A.data, Symbol(A.uplo), issymmetric(A)) factorize(A::HermOrSym) = bkfact(A) diff --git a/test/linalg/symmetric.jl b/test/linalg/symmetric.jl index 452637898f361..80e1976abad7b 100644 --- a/test/linalg/symmetric.jl +++ b/test/linalg/symmetric.jl @@ -250,3 +250,36 @@ let a = randn(2,2) cc = copy(c) @test conj!(c) == conj(Array(c)) end + +# 19225 +let X = [1 -1; -1 1] + for T in (Symmetric, Hermitian) + Y = T(copy(X)) + _Y = similar(Y) + copy!(_Y, Y) + @test _Y == Y + + W = T(copy(X), :L) + copy!(W, Y) + @test W.data == Y.data + @test W.uplo != Y.uplo + + W[1,1] = 4 + @test W == T([4 -1; -1 1]) + @test_throws ArgumentError (W[1,2] = 2) + + @test Y + I == T([2 -1; -1 2]) + @test Y - I == T([0 -1; -1 0]) + @test Y * I == Y + + @test Y + 1 == T([2 0; 0 2]) + @test Y - 1 == T([0 -2; -2 0]) + @test Y * 2 == T([2 -2; -2 2]) + @test Y / 1 == Y + + @test T([true false; false true]) + true == T([2 1; 1 2]) + end + + @test_throws ArgumentError Hermitian(X) + 2im*I + @test_throws ArgumentError Hermitian(X) - 2im*I +end diff --git a/test/sparse/sparse.jl b/test/sparse/sparse.jl index b56ad98a84d97..72aef1cbe1ef0 100644 --- a/test/sparse/sparse.jl +++ b/test/sparse/sparse.jl @@ -1635,3 +1635,31 @@ let @test isa(abs.(A), SparseMatrixCSC) # representative for _unary_nz2nz_z2z class @test isa(exp.(A), Array) # representative for _unary_nz2nz_z2nz class end + +# 19225 +let X = sparse([1 -1; -1 1]) + for T in (Symmetric, Hermitian) + Y = T(copy(X)) + _Y = similar(Y) + copy!(_Y, Y) + @test _Y == Y + + W = T(copy(X), :L) + copy!(W, Y) + @test W.data == Y.data + @test W.uplo != Y.uplo + + W[1,1] = 4 + @test W == T(sparse([4 -1; -1 1])) + @test_throws ArgumentError (W[1,2] = 2) + + @test Y + I == T(sparse([2 -1; -1 2])) + @test Y - I == T(sparse([0 -1; -1 0])) + @test Y * I == Y + + @test Y + 1 == T(sparse([2 0; 0 2])) + @test Y - 1 == T(sparse([0 -2; -2 0])) + @test Y * 2 == T(sparse([2 -2; -2 2])) + @test Y / 1 == Y + end +end