Skip to content

Commit 8517783

Browse files
committed
catch non-full sparse matrices and simplify diagonal implementation
1 parent 1bf5e76 commit 8517783

File tree

5 files changed

+51
-21
lines changed

5 files changed

+51
-21
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
88
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
99
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
1010
DerivableInterfaces = "6c5e35bf-e59e-4898-b73c-732dcc4ba65f"
11+
DiagonalArrays = "74fd4be6-21e2-4f6f-823a-4360d37c7a77"
1112
Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
1213
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
1314
GradedUnitRanges = "e2de450a-8a67-46c7-b59c-01d5a3d041c5"
@@ -32,6 +33,7 @@ Aqua = "0.8.9"
3233
ArrayLayouts = "1.10.4"
3334
BlockArrays = "1.2.0"
3435
DerivableInterfaces = "0.3.7"
36+
DiagonalArrays = "0.2.2"
3537
Dictionaries = "0.4.3"
3638
FillArrays = "1.13.0"
3739
GPUArraysCore = "0.1.0, 0.2"

src/abstractblocksparsearray/abstractblocksparsematrix.jl

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ function _allocate_svd_output(A::AbstractBlockSparseMatrix, full::Bool, ::Algori
4343

4444
# fill in values for blocks that aren't present, pairing them in order of occurence
4545
# this is a convention, which at least gives the expected results for blockdiagonal
46-
emptyrows = findall((browIs), 1:bmn)
47-
emptycols = findall((bcolIs), 1:bmn)
46+
emptyrows = findall((browIs), 1:bm)
47+
emptycols = findall((bcolIs), 1:bn)
4848
for (row, col) in zip(emptyrows, emptycols)
4949
slengths[col] = min(brows[row], bcols[col])
5050
end
@@ -73,5 +73,20 @@ function svd!(
7373
S[bcol] = bUSV.S
7474
Vt[bcol, bcol] = bUSV.Vt
7575
end
76+
77+
# fill in values for blocks that aren't present, pairing them in order of occurence
78+
block_inds_S = eachblockstoredindex(S)
79+
i = findfirst((block_inds_S), blockaxes(S, 1))
80+
bIs = collect(eachblockstoredindex(U))
81+
browIs = Int.(first.(Tuple.(bIs)))
82+
emptyrows = findall((browIs), 1:blocksize(U, 1))
83+
j = 0
84+
while !isnothing(i)
85+
copyto!(@view!(Vt[Block(i), Block(i)]), LinearAlgebra.I)
86+
j += 1
87+
copyto!(@view!(U[Block(emptyrows[j]), Block(i)]), LinearAlgebra.I)
88+
i = findnext((block_inds_S), blockaxes(S, 1), i + 1)
89+
end
90+
7691
return SVD(U, S, Vt)
7792
end

src/blocksparsearray/blockdiagonalarray.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# type alias for block-diagonal
22
using LinearAlgebra: Diagonal
3+
using DiagonalArrays: DiagonalArrays, diagonal
34

45
const BlockDiagonal{T,A,Axes,V<:AbstractVector{A}} = BlockSparseMatrix{
56
T,A,Diagonal{A,V},Axes
@@ -15,3 +16,11 @@ function BlockDiagonal(blocks::AbstractVector{<:AbstractMatrix})
1516
Diagonal(blocks), (blockedrange(size.(blocks, 1)), blockedrange(size.(blocks, 2)))
1617
)
1718
end
19+
20+
function DiagonalArrays.diagonal(S::BlockSparseVector)
21+
D = similar(S, (axes(S, 1), axes(S, 1)))
22+
for bI in eachblockstoredindex(S)
23+
D[bI, bI] = diagonal(@view!(S[bI]))
24+
end
25+
return D
26+
end

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
44
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
55
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
66
BlockSparseArrays = "2c9a651f-6452-4ace-a6ac-809f4280fbb4"
7+
DiagonalArrays = "74fd4be6-21e2-4f6f-823a-4360d37c7a77"
78
GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527"
89
GradedUnitRanges = "e2de450a-8a67-46c7-b59c-01d5a3d041c5"
910
JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb"

test/basics/test_svd.jl

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using Test
22
using BlockSparseArrays
3-
using BlockSparseArrays: BlockSparseArray, svd, BlockDiagonal
3+
using BlockSparseArrays: BlockSparseArray, svd, BlockDiagonal, eachblockstoredindex
44
using BlockArrays
5-
using LinearAlgebra: LinearAlgebra, Diagonal, svdvals
65
using Random
6+
using DiagonalArrays: diagonal
7+
using LinearAlgebra: LinearAlgebra
78

89
function test_svd(a, usv)
910
U, S, V = usv
1011

11-
@test U * Diagonal(S) * V' a
12+
@test U * diagonal(S) * V' a
1213
@test U' * U LinearAlgebra.I
1314
@test V' * V LinearAlgebra.I
1415
end
@@ -43,33 +44,35 @@ end
4344
usv = svd(a)
4445
# TODO: `BlockDiagonal * Adjoint` errors
4546
test_svd(a, usv)
46-
@test usv.U isa BlockDiagonal
47-
@test usv.Vt isa BlockDiagonal
48-
@test usv.S isa BlockVector
4947
end
5048

51-
a = mortar([rand(2, 2) for i in 1:2, j in 1:3])
52-
usv = svd(a)
53-
test_svd(a, usv)
54-
55-
a = mortar([rand(2, 2) for i in 1:3, j in 1:2])
56-
usv = svd(a)
57-
test_svd(a, usv)
58-
5949
# blocksparse
6050
# -----------
6151
@testset "($m, $n) BlockSparseMatrix{$T}" for ((m, n), T) in
6252
Iterators.product(blockszs, eltypes)
6353
a = BlockSparseArray{T}(m, n)
54+
55+
# test empty matrix
56+
usv_empty = svd(a)
57+
test_svd(a, usv_empty)
58+
59+
# test blockdiagonal
6460
for i in LinearAlgebra.diagind(blocks(a))
6561
I = CartesianIndices(blocks(a))[i]
6662
a[Block(I.I...)] = rand(T, size(blocks(a)[i]))
6763
end
68-
perm = Random.randperm(length(m))
69-
a = a[Block.(perm), Block.(1:length(n))]
70-
71-
# errors because `blocks(a)[CartesianIndex.(...)]` is not implemented
7264
usv = svd(a)
73-
# TODO: `BlockDiagonal * Adjoint` errors
7465
test_svd(a, usv)
66+
67+
perm = Random.randperm(length(m))
68+
b = a[Block.(perm), Block.(1:length(n))]
69+
usv = svd(b)
70+
test_svd(b, usv)
71+
72+
# test permuted blockdiagonal with missing row/col
73+
I_removed = rand(eachblockstoredindex(b))
74+
c = copy(b)
75+
delete!(blocks(c).storage, CartesianIndex(Int.(Tuple(I_removed))))
76+
usv = svd(c)
77+
test_svd(c, usv)
7578
end

0 commit comments

Comments
 (0)