Skip to content

Commit 5879fe4

Browse files
author
Glenn Moynihan
authored
Merge pull request #17 from invenia/gm/submat
Define submat for PDMat subtypes
2 parents 54bbbf9 + 1eb6f49 commit 5879fe4

File tree

6 files changed

+116
-23
lines changed

6 files changed

+116
-23
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
name = "PDMatsExtras"
22
uuid = "2c7acb1b-7338-470f-b38f-951d2bcb9193"
33
authors = ["Invenia Technical Computing"]
4-
version = "2.4.0"
4+
version = "2.5.0"
55

66
[deps]
77
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
88
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
99
PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150"
10+
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
11+
SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
1012

1113
[compat]
1214
ChainRulesCore = "0.9.17, 0.10"

src/PDMatsExtras.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ module PDMatsExtras
22
using ChainRulesCore
33
using LinearAlgebra
44
using PDMats
5+
using SparseArrays: sparse
6+
using SuiteSparse
57
import Base: *, \
68

79
export PSDMat, WoodburyPDMat
10+
export submat
811

912
include("psd_mat.jl")
1013
include("woodbury_pd_mat.jl")
14+
include("utils.jl")
1115

1216
end

src/utils.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
submat(A::AbstractPDMat, inds)
3+
4+
Select a square submatrix of an `AbstractPDMat` specified by `inds`.
5+
Returns a `AbstractPDMat` of the same type.
6+
"""
7+
submat(A::PDMat, inds) = PDMat(A[inds, inds])
8+
submat(A::PSDMat, inds) = PSDMat(A[inds, inds])
9+
submat(A::PDiagMat, inds) = PDiagMat(A.diag[inds])
10+
submat(A::PDSparseMat, inds) = PDSparseMat(sparse(A[inds, inds]))
11+
submat(A::WoodburyPDMat, inds) = WoodburyPDMat(A.A[inds, :], A.D, Diagonal(A.S.diag[inds]))
12+
function submat(A::ScalMat, inds)
13+
# inds should not be able to "access" non-existent indices
14+
checkbounds(Bool, A, inds) || throw(BoundsError(A, inds))
15+
return ScalMat(length(inds), A.value)
16+
end

test/psd_mat.jl

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,3 @@
1-
2-
# NOTE: We could probably do a more thorough testing job if we able to override the
3-
# `t_tripod` and `t_whiten` test in PDMats.
4-
test_matrices = Dict(
5-
"Positive definite" => [
6-
0.796911 0.602112 0.766136 0.247788
7-
0.602112 0.480312 0.605538 0.218218
8-
0.766136 0.605538 1.28666 0.290052
9-
0.247788 0.218218 0.290052 0.130588
10-
],
11-
"Positive semi-definite" => [
12-
10.8145 -9.27226 1.67126 4.02515
13-
-9.27226 8.08443 -1.48168 -4.27258
14-
1.67126 -1.48168 1.31866 1.43293
15-
4.02515 -4.27258 1.43293 6.76801
16-
]
17-
)
18-
191
# We write the tests like this to match the style of `testutils.jl`.
202
# We define this here, rather than in `testutils.jl` because we're not allowed to change the
213
# contents of that file, which should always match the PDMats v0.10 version of that file
@@ -35,7 +17,7 @@ end
3517
@testset "PSDMat" begin
3618
verbose = 1
3719
@testset "Positive definite" begin
38-
M = test_matrices["Positive definite"]
20+
M = TEST_MATRICES["Positive definite"]
3921
pivoted = cholesky(M, Val(true))
4022
C = PSDMat(M, pivoted)
4123
test_pdmat(
@@ -49,7 +31,7 @@ end
4931
pdtest_kron(C, C.mat, verbose)
5032
end
5133
@testset "Positive semi-definite" begin
52-
M = test_matrices["Positive semi-definite"]
34+
M = TEST_MATRICES["Positive semi-definite"]
5335
@test !isposdef(M)
5436
pivoted = cholesky(M, Val(true); check=false)
5537
C = PSDMat(M, pivoted)
@@ -74,7 +56,7 @@ end
7456
n_tsamples = 10^6
7557

7658
@testset "Positive definite" begin
77-
g = MvNormal(means, PSDMat(test_matrices["Positive definite"]))
59+
g = MvNormal(means, PSDMat(TEST_MATRICES["Positive definite"]))
7860
d = length(g)
7961
μ = mean(g)
8062
Σ = cov(g)
@@ -119,7 +101,7 @@ end
119101
end
120102

121103
@testset "Positive semi-definite" begin
122-
g = MvNormal(means, PSDMat(test_matrices["Positive semi-definite"]))
104+
g = MvNormal(means, PSDMat(TEST_MATRICES["Positive semi-definite"]))
123105
d = length(g)
124106
μ = mean(g)
125107
Σ = cov(g)

test/runtests.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,35 @@ using Distributions
44
using FiniteDifferences
55
using LinearAlgebra
66
using PDMats
7+
using SparseArrays: sparse
78
using Random
89
using Test
910
using Zygote
1011

1112
Random.seed!(1)
13+
14+
# NOTE: We could probably do a more thorough testing job if we able to override the
15+
# `t_tripod` and `t_whiten` test in PDMats.
16+
const TEST_MATRICES = Dict(
17+
"Positive definite" => [
18+
0.796911 0.602112 0.766136 0.247788
19+
0.602112 0.480312 0.605538 0.218218
20+
0.766136 0.605538 1.28666 0.290052
21+
0.247788 0.218218 0.290052 0.130588
22+
],
23+
"Positive semi-definite" => [
24+
10.8145 -9.27226 1.67126 4.02515
25+
-9.27226 8.08443 -1.48168 -4.27258
26+
1.67126 -1.48168 1.31866 1.43293
27+
4.02515 -4.27258 1.43293 6.76801
28+
]
29+
)
30+
1231
@testset "PDMatsExtras.jl" begin
1332
include("testutils.jl")
1433
include("test_ad.jl")
1534

1635
include("psd_mat.jl")
1736
include("woodbury_pd_mat.jl")
37+
include("utils.jl")
1838
end

test/utils.jl

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
@testset "utils.jl" begin
2+
@testset "submat" begin
3+
4+
@testset "PDMat" begin
5+
M = PDMat(TEST_MATRICES["Positive definite"])
6+
M_dense = Matrix(M)
7+
8+
subM = submat(M, [1, 3])
9+
@test subM isa PDMat
10+
@test Matrix(subM) == M_dense[[1, 3], [1, 3]]
11+
end
12+
13+
@testset "PDDiagMat" begin
14+
M = PDiagMat(diag(TEST_MATRICES["Positive definite"]))
15+
M_dense = Matrix(M)
16+
17+
subM = submat(M, [1, 3])
18+
@test subM isa PDiagMat
19+
@test Matrix(subM) == M_dense[[1, 3], [1, 3]]
20+
end
21+
22+
@testset "PDSparseMat" begin
23+
M = PDSparseMat(sparse(TEST_MATRICES["Positive definite"]))
24+
M_dense = Matrix(M)
25+
26+
subM = submat(M, [1, 3])
27+
@test subM isa PDSparseMat
28+
@test Matrix(subM) == M_dense[[1, 3], [1, 3]]
29+
end
30+
31+
@testset "ScalMat" begin
32+
M = ScalMat(3, 0.1)
33+
M_dense = Matrix(M)
34+
35+
subM = submat(M, [1, 3])
36+
@test subM isa ScalMat
37+
@test Matrix(subM) == M_dense[[1, 3], [1, 3]]
38+
@test_throws BoundsError submat(M, [1, 10])
39+
end
40+
41+
@testset "PSDMat" begin
42+
SM = TEST_MATRICES["Positive semi-definite"]
43+
pivoted = cholesky(SM, Val(true); check=false)
44+
M = PSDMat(SM, pivoted)
45+
M_dense = Matrix(M)
46+
47+
subM = submat(M, [1, 3])
48+
@test subM isa PSDMat
49+
@test Matrix(subM) == M_dense[[1, 3], [1, 3]]
50+
end
51+
52+
@testset "WoodburyPDMat" begin
53+
A = randn(4, 2)
54+
D = Diagonal(randn(2).^2 .+ 1)
55+
S = Diagonal(randn(4).^2 .+ 1)
56+
x = randn(size(A, 1))
57+
58+
W = WoodburyPDMat(A, D, S)
59+
W_dense = PDMat(Symmetric(Matrix(W)))
60+
61+
subW = submat(W, [1, 3])
62+
@test subW isa WoodburyPDMat
63+
@test subW.A == W.A[[1, 3], :]
64+
@test subW.D == W.D
65+
@test subW.S == Diagonal(W.S.diag[[1, 3]])
66+
@test Matrix(subW) == W_dense[[1, 3], [1, 3]]
67+
end
68+
end
69+
end

0 commit comments

Comments
 (0)