Skip to content

Commit

Permalink
add option for read-only off-diagonal elements
Browse files Browse the repository at this point in the history
  • Loading branch information
bjarthur committed Jan 18, 2022
1 parent fab91c2 commit c249450
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 13 deletions.
28 changes: 17 additions & 11 deletions src/PackedArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import LinearAlgebra: mul!, BLAS, BlasFloat, generic_matvecmul!, MulAddMul

export SymmetricPacked

struct SymmetricPacked{T,S<:AbstractMatrix{T}} <: AbstractMatrix{T}
struct SymmetricPacked{T,S<:AbstractMatrix{T},V} <: AbstractMatrix{T}
tri::Vector{T}
n::Int
uplo::Char

function SymmetricPacked{T,S}(tri, n, uplo) where {T,S<:AbstractMatrix{T}}
function SymmetricPacked{T,S,V}(tri, n, uplo) where {T,S<:AbstractMatrix{T},V}
require_one_based_indexing(tri)
uplo=='U' || uplo=='L' || throw(ArgumentError("uplo must be either 'U' (upper) or 'L' (lower)"))
new{T,S}(tri, n, uplo)
new{T,S,V}(tri, n, uplo)
end
end

Expand All @@ -33,10 +33,11 @@ function pack(A::AbstractMatrix{T}, uplo::Symbol) where {T}
end

"""
SymmetricPacked(A, uplo=:U)
SymmetricPacked(A, uplo=:U, offdiag=Val(:RO))
Construct a `Symmetric` matrix in packed form of the upper (if `uplo = :U`)
or lower (if `uplo = :L`) triangle of the matrix `A`.
or lower (if `uplo = :L`) triangle of the matrix `A`. `offdiag` specifies
whether elements not on the diagaonal can be set (if `:RW`) or not (if `:RO`).
# Examples
```jldoctest
Expand All @@ -63,20 +64,20 @@ julia> Base.summarysize(AP)
184
```
"""
function SymmetricPacked(A::AbstractMatrix{T}, uplo::Symbol=:U) where {T}
function SymmetricPacked(A::AbstractMatrix{T}, uplo::Symbol=:U, offdiag=Val(:RO)) where {T}
n = checksquare(A)
SymmetricPacked{T,AbstractMatrix{T}}(pack(A, uplo), n, char_uplo(uplo))
SymmetricPacked{T,AbstractMatrix{T},offdiag}(pack(A, uplo), n, char_uplo(uplo))
end

function SymmetricPacked(x::SymmetricPacked{T,S}) where{T,S}
SymmetricPacked{T,S}(T.(x.tri), x.n, x.uplo)
function SymmetricPacked(x::SymmetricPacked{T,S,V}) where{T,S,V}
SymmetricPacked{T,S,V}(T.(x.tri), x.n, x.uplo)
end

checksquare(x::SymmetricPacked) = x.n

convert(::Type{SymmetricPacked{T,S}}, x::SymmetricPacked) where {T,S} = SymmetricPacked{T,S}(T.(x.tri), x.n, x.uplo)
convert(::Type{SymmetricPacked{T,S,V}}, x::SymmetricPacked) where {T,S,V} = SymmetricPacked{T,S}(T.(x.tri), x.n, x.uplo)

unsafe_convert(::Type{Ptr{T}}, A::SymmetricPacked{T,S}) where {T,S} = Base.unsafe_convert(Ptr{T}, A.tri)
unsafe_convert(::Type{Ptr{T}}, A::SymmetricPacked{T,S,V}) where {T,S,V} = Base.unsafe_convert(Ptr{T}, A.tri)

size(A::SymmetricPacked) = (A.n,A.n)

Expand All @@ -97,6 +98,11 @@ end
return r
end

function setindex!(A::SymmetricPacked{T,S,Val(:RO)}, v, i::Int, j::Int) where {T,S}
i!=j && throw(ArgumentError("Cannot set a non-diagonal index in a symmetric matrix"))
setindex!(A, v, i, j)
end

function setindex!(A::SymmetricPacked, v, i::Int, j::Int)
@boundscheck checkbounds(A, i, j)
if A.uplo=='U'
Expand Down
11 changes: 9 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ using PackedArrays, Test, LinearAlgebra
A = collect(reshape(1:9.0,3,3))

@testset "upper triangle" begin
APU = SymmetricPacked(A, :U)
APU = SymmetricPacked(A, :U, Val(:RW))

@test APU[1,1] == A[1,1]
@test APU[1,2] == A[1,2]
Expand All @@ -20,7 +20,7 @@ A = collect(reshape(1:9.0,3,3))
end

@testset "lower triangle" begin
APL = SymmetricPacked(A, :L)
APL = SymmetricPacked(A, :L, Val(:RW))

@test APL[1,1] == A[1,1]
@test APL[1,2] == A[2,1]
Expand All @@ -36,6 +36,13 @@ end
@test APL[2,1] == 0
end

@testset "read-only" begin
APL = SymmetricPacked(A, :L)
@test_throws ArgumentError APL[1,3]=3
APL = SymmetricPacked(A, :L, Val(:RO))
@test_throws ArgumentError APL[1,3]=3
end

@testset "mul!" begin
for uplo in [:U, :L]
y = Float64[1,2,3]
Expand Down

0 comments on commit c249450

Please sign in to comment.