Skip to content

Commit 0ee1379

Browse files
committed
add option for writable off-diagonal elements
1 parent 2e6a6f9 commit 0ee1379

File tree

3 files changed

+100
-15
lines changed

3 files changed

+100
-15
lines changed

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,47 @@ julia> mul!(copy(y), AP, x, α, β) # or use the equivalent julian interface
9797
0.9592679333345454
9898
0.27783932357851576
9999
```
100+
101+
`SymmetricPacked` differs in one important aspect to `LinearAlgebra.Symmetric`
102+
in that it optionally permits off diagonal elements to be set. Continuing
103+
from the example above:
104+
105+
```
106+
julia> AP[1,1]=5
107+
5
108+
109+
julia> AP
110+
5×5 SymmetricPacked{Float64, Matrix{Float64}, Val{:RO}()}:
111+
5.0 0.736451 0.704095 0.842738 0.207618
112+
0.736451 0.63549 0.861638 0.834968 0.0660772
113+
0.704095 0.861638 0.131074 0.727387 0.0995039
114+
0.842738 0.834968 0.727387 0.96513 0.616451
115+
0.207618 0.0660772 0.0995039 0.616451 0.369353
116+
117+
julia> AP[1,5]=5
118+
ERROR: ArgumentError: Cannot set a non-diagonal index in a symmetric matrix
119+
Stacktrace:
120+
[1] setindex!(A::SymmetricPacked{Float64, Matrix{Float64}, Val{:RO}()}, v::Int64, i::Int64, j::Int64)
121+
@ PackedArrays ~/projects/darshan/PackedArrays/src/PackedArrays.jl:114
122+
[2] top-level scope
123+
@ REPL[7]:1
124+
125+
julia> APRW = SymmetricPacked(A, :L, Val(:RW)) # default is :RO
126+
5×5 SymmetricPacked{Float64, Matrix{Float64}, Val{:RW}()}:
127+
0.364856 0.0797498 0.152769 0.201612 0.283603
128+
0.0797498 0.63549 0.00271082 0.0429332 0.818754
129+
0.152769 0.00271082 0.131074 0.682401 0.76548
130+
0.201612 0.0429332 0.682401 0.96513 0.284176
131+
0.283603 0.818754 0.76548 0.284176 0.369353
132+
133+
julia> APRW[1,5]=5
134+
5
135+
136+
julia> APRW
137+
5×5 SymmetricPacked{Float64, Matrix{Float64}, Val{:RW}()}:
138+
0.364856 0.0797498 0.152769 0.201612 5.0
139+
0.0797498 0.63549 0.00271082 0.0429332 0.818754
140+
0.152769 0.00271082 0.131074 0.682401 0.76548
141+
0.201612 0.0429332 0.682401 0.96513 0.284176
142+
5.0 0.818754 0.76548 0.284176 0.369353
143+
```

src/SymmetricFormats.jl

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import LinearAlgebra: mul!, BLAS, BlasFloat, generic_matvecmul!, MulAddMul
77

88
export SymmetricPacked
99

10-
struct SymmetricPacked{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T}
10+
struct SymmetricPacked{T,S<:AbstractMatrix{<:T},V} <: AbstractMatrix{T}
1111
tri::Vector{T}
1212
n::Int
1313
uplo::Char
1414

15-
function SymmetricPacked{T,S}(tri, n, uplo) where {T,S<:AbstractMatrix{<:T}}
15+
function SymmetricPacked{T,S,V}(tri, n, uplo) where {T,S<:AbstractMatrix{<:T},V}
1616
require_one_based_indexing(tri)
1717
uplo=='U' || uplo=='L' || throw(ArgumentError("uplo must be either 'U' (upper) or 'L' (lower)"))
18-
new{T,S}(tri, n, uplo)
18+
new{T,S,V}(tri, n, uplo)
1919
end
2020
end
2121

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

3535
"""
36-
SymmetricPacked(A, uplo=:U)
36+
SymmetricPacked(A, uplo=:U, offdiag=Val(:RO))
3737
3838
Construct a `Symmetric` matrix in packed form of the upper (if `uplo = :U`)
39-
or lower (if `uplo = :L`) triangle of the matrix `A`.
39+
or lower (if `uplo = :L`) triangle of the matrix `A`. `offdiag` specifies
40+
whether elements not on the diagaonal can be set (if `:RW`) or not (if `:RO`).
4041
4142
# Examples
4243
```jldoctest
@@ -63,20 +64,20 @@ julia> Base.summarysize(AP)
6364
184
6465
```
6566
"""
66-
function SymmetricPacked(A::AbstractMatrix{T}, uplo::Symbol=:U) where {T}
67+
function SymmetricPacked(A::AbstractMatrix{T}, uplo::Symbol=:U, offdiag=Val(:RO)) where {T}
6768
n = checksquare(A)
68-
SymmetricPacked{T,typeof(A)}(pack(A, uplo), n, char_uplo(uplo))
69+
SymmetricPacked{T,typeof(A),offdiag}(pack(A, uplo), n, char_uplo(uplo))
6970
end
7071

71-
function SymmetricPacked(x::SymmetricPacked{T,S}) where{T,S}
72-
SymmetricPacked{T,S}(T.(x.tri), x.n, x.uplo)
72+
function SymmetricPacked(x::SymmetricPacked{T,S,V}) where{T,S,V}
73+
SymmetricPacked{T,S,V}(T.(x.tri), x.n, x.uplo)
7374
end
7475

7576
checksquare(x::SymmetricPacked) = x.n
7677

77-
convert(::Type{SymmetricPacked{T,S}}, x::SymmetricPacked) where {T,S} = SymmetricPacked{T,S}(T.(x.tri), x.n, x.uplo)
78+
convert(::Type{SymmetricPacked{T,S,V}}, x::SymmetricPacked) where {T,S,V} = SymmetricPacked{T,S}(T.(x.tri), x.n, x.uplo)
7879

79-
unsafe_convert(::Type{Ptr{T}}, A::SymmetricPacked{T,S}) where {T,S} = Base.unsafe_convert(Ptr{T}, A.tri)
80+
unsafe_convert(::Type{Ptr{T}}, A::SymmetricPacked{T,S,V}) where {T,S,V} = Base.unsafe_convert(Ptr{T}, A.tri)
8081

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

@@ -97,8 +98,7 @@ end
9798
return r
9899
end
99100

100-
function setindex!(A::SymmetricPacked, v, i::Int, j::Int)
101-
i!=j && throw(ArgumentError("Cannot set a non-diagonal index in a symmetric matrix"))
101+
function _setindex!(A::SymmetricPacked, v, i::Int, j::Int)
102102
@boundscheck checkbounds(A, i, j)
103103
if A.uplo=='U'
104104
i,j = minmax(i,j)
@@ -110,15 +110,22 @@ function setindex!(A::SymmetricPacked, v, i::Int, j::Int)
110110
return v
111111
end
112112

113+
function setindex!(A::SymmetricPacked{T,S,Val(:RO)}, v, i::Int, j::Int) where {T,S}
114+
i!=j && throw(ArgumentError("Cannot set a non-diagonal index in a symmetric matrix"))
115+
_setindex!(A, v, i, j)
116+
end
117+
118+
setindex!(A::SymmetricPacked{T,S,Val(:RW)}, v, i::Int, j::Int) where {T,S} = _setindex!(A, v, i, j)
119+
113120
function copy(A::SymmetricPacked{T,S}) where {T,S}
114121
B = copy(A.tri)
115122
SymmetricPacked{T,S}(B, A.n, A.uplo)
116123
end
117124

118125
@inline function mul!(y::StridedVector{T},
119-
AP::SymmetricPacked{T,<:StridedMatrix},
126+
AP::SymmetricPacked{T,<:StridedMatrix,V},
120127
x::StridedVector{T},
121-
α::Number, β::Number) where {T<:BlasFloat}
128+
α::Number, β::Number) where {T<:BlasFloat,V}
122129
alpha, beta = promote(α, β, zero(T))
123130
if alpha isa Union{Bool,T} && beta isa Union{Bool,T}
124131
BLAS.spmv!(AP.uplo, alpha, AP.tri, x, beta, y)

test/runtests.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,40 @@ A = collect(reshape(1:9.0,3,3))
99
@test_throws ArgumentError APL[1,3]=3
1010
end
1111

12+
@testset "read/write upper" begin
13+
APU = SymmetricPacked(A, :U, Val(:RW))
14+
15+
@test APU[1,1] == A[1,1]
16+
@test APU[1,2] == A[1,2]
17+
@test APU[1,3] == A[1,3]
18+
@test APU[2,1] == A[1,2]
19+
@test APU[2,2] == A[2,2]
20+
@test APU[2,3] == A[2,3]
21+
@test APU[3,1] == A[1,3]
22+
@test APU[3,2] == A[2,3]
23+
@test APU[3,3] == A[3,3]
24+
25+
APU[1,2] = 0
26+
@test APU[2,1] == 0
27+
end
28+
29+
@testset "read/write lower" begin
30+
APL = SymmetricPacked(A, :L, Val(:RW))
31+
32+
@test APL[1,1] == A[1,1]
33+
@test APL[1,2] == A[2,1]
34+
@test APL[1,3] == A[3,1]
35+
@test APL[2,1] == A[2,1]
36+
@test APL[2,2] == A[2,2]
37+
@test APL[2,3] == A[3,2]
38+
@test APL[3,1] == A[3,1]
39+
@test APL[3,2] == A[3,2]
40+
@test APL[3,3] == A[3,3]
41+
42+
APL[1,2] = 0
43+
@test APL[2,1] == 0
44+
end
45+
1246
@testset "mul!" begin
1347
for uplo in [:U, :L]
1448
y = Float64[1,2,3]

0 commit comments

Comments
 (0)