Skip to content

Commit 1bc091a

Browse files
authored
[BlockSparseArrays] Sub-slices of multiple blocks (#1489)
* [BlockSparseArrays] Sub-slices of multiple blocks * [NDTensors] Bump to v0.3.24
1 parent d70b89e commit 1bc091a

File tree

6 files changed

+149
-19
lines changed

6 files changed

+149
-19
lines changed

NDTensors/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "NDTensors"
22
uuid = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf"
33
authors = ["Matthew Fishman <[email protected]>"]
4-
version = "0.3.23"
4+
version = "0.3.24"
55

66
[deps]
77
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"

NDTensors/src/lib/BlockSparseArrays/src/BlockArraysExtensions/BlockArraysExtensions.jl

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ function blockrange(axis::AbstractUnitRange, r::UnitRange)
159159
end
160160

161161
function blockrange(axis::AbstractUnitRange, r::Int)
162-
error("Slicing with integer values isn't supported.")
163-
return findblock(axis, r)
162+
## return findblock(axis, r)
163+
return error("Slicing with integer values isn't supported.")
164164
end
165165

166166
function blockrange(axis::AbstractUnitRange, r::AbstractVector{<:Block{1}})
@@ -187,6 +187,24 @@ function blockrange(axis::AbstractUnitRange, r::BlockIndexRange)
187187
return Block(r):Block(r)
188188
end
189189

190+
function blockrange(axis::AbstractUnitRange, r::AbstractVector{<:BlockIndexRange{1}})
191+
return error("Slicing not implemented for range of type `$(typeof(r))`.")
192+
end
193+
194+
function blockrange(
195+
axis::AbstractUnitRange,
196+
r::BlockVector{BlockIndex{1},<:AbstractVector{<:BlockIndexRange{1}}},
197+
)
198+
return map(b -> Block(b), blocks(r))
199+
end
200+
201+
# This handles slicing with `:`/`Colon()`.
202+
function blockrange(axis::AbstractUnitRange, r::Base.Slice)
203+
# TODO: Maybe use `BlockRange`, but that doesn't output
204+
# the same thing.
205+
return only(blockaxes(axis))
206+
end
207+
190208
function blockrange(axis::AbstractUnitRange, r)
191209
return error("Slicing not implemented for range of type `$(typeof(r))`.")
192210
end
@@ -228,6 +246,22 @@ function blockindices(a::AbstractUnitRange, b::Block, r::BlockIndices)
228246
return blockindices(a, b, r.blocks)
229247
end
230248

249+
function blockindices(
250+
a::AbstractUnitRange,
251+
b::Block,
252+
r::BlockVector{BlockIndex{1},<:AbstractVector{<:BlockIndexRange{1}}},
253+
)
254+
# TODO: Change to iterate over `BlockRange(r)`
255+
# once https://github.com/JuliaArrays/BlockArrays.jl/issues/404
256+
# is fixed.
257+
for bl in blocks(r)
258+
if b == Block(bl)
259+
return only(bl.indices)
260+
end
261+
end
262+
return error("Block not found.")
263+
end
264+
231265
function cartesianindices(a::AbstractArray, b::Block)
232266
return cartesianindices(axes(a), b)
233267
end

NDTensors/src/lib/BlockSparseArrays/src/abstractblocksparsearray/wrappedabstractblocksparsearray.jl

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Adapt: Adapt, WrappedArray
2-
using BlockArrays: BlockArrays, BlockedUnitRange, BlockRange, blockedrange, unblock
2+
using BlockArrays:
3+
BlockArrays, BlockedUnitRange, BlockIndexRange, BlockRange, blockedrange, mortar, unblock
34
using SplitApplyCombine: groupcount
45

56
const WrappedAbstractBlockSparseArray{T,N} = WrappedArray{
@@ -46,6 +47,15 @@ function Base.to_indices(
4647
return blocksparse_to_indices(a, I)
4748
end
4849

50+
# Handle case of indexing with `[Block(1)[1:2], Block(2)[1:2]]`
51+
# by converting it to a `BlockVector` with
52+
# `mortar([Block(1)[1:2], Block(2)[1:2]])`.
53+
function Base.to_indices(
54+
a::BlockSparseArrayLike, inds, I::Tuple{AbstractVector{<:BlockIndexRange{1}},Vararg{Any}}
55+
)
56+
return to_indices(a, inds, (mortar(I[1]), Base.tail(I)...))
57+
end
58+
4959
# Fixes ambiguity error with BlockArrays.
5060
function Base.to_indices(a::BlockSparseArrayLike, I::Tuple{BlockRange{1},Vararg{Any}})
5161
return blocksparse_to_indices(a, I)
@@ -126,14 +136,25 @@ function Base.getindex(
126136
return blocksparse_getindex(a, block...)
127137
end
128138

129-
# TODO: Define `issasigned(a, ::Block{N})`.
139+
# TODO: Define `blocksparse_isassigned`.
130140
function Base.isassigned(
131141
a::BlockSparseArrayLike{<:Any,N}, index::Vararg{Block{1},N}
132142
) where {N}
133-
# TODO: Define `blocksparse_isassigned`.
134143
return isassigned(blocks(a), Int.(index)...)
135144
end
136145

146+
function Base.isassigned(a::BlockSparseArrayLike{<:Any,N}, index::Block{N}) where {N}
147+
return isassigned(a, Tuple(index)...)
148+
end
149+
150+
# TODO: Define `blocksparse_isassigned`.
151+
function Base.isassigned(
152+
a::BlockSparseArrayLike{<:Any,N}, index::Vararg{BlockIndex{1},N}
153+
) where {N}
154+
b = block.(index)
155+
return isassigned(a, b...) && isassigned(@view(a[b...]), blockindex.(index)...)
156+
end
157+
137158
function Base.setindex!(a::BlockSparseArrayLike{<:Any,N}, value, I::BlockIndex{N}) where {N}
138159
blocksparse_setindex!(a, value, I)
139160
return a

NDTensors/src/lib/BlockSparseArrays/test/test_basics.jl

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
@eval module $(gensym())
22
using BlockArrays:
3-
Block, BlockRange, BlockedUnitRange, BlockVector, blockedrange, blocklength, blocksize
3+
Block,
4+
BlockRange,
5+
BlockedUnitRange,
6+
BlockVector,
7+
blockedrange,
8+
blocklength,
9+
blocklengths,
10+
blocksize,
11+
mortar
412
using LinearAlgebra: mul!
513
using NDTensors.BlockSparseArrays: BlockSparseArray, block_nstored, block_reshape
614
using NDTensors.SparseArrayInterface: nstored
@@ -331,13 +339,69 @@ include("TestBlockSparseArraysUtils.jl")
331339
@test b[4, 4] == 44
332340
end
333341

334-
# This is outputting only zero blocks.
335342
a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4]))
336-
a[Block(1, 2)] = randn(elt, size(@view(a[Block(1, 2)])))
337-
a[Block(2, 1)] = randn(elt, size(@view(a[Block(2, 1)])))
343+
@views for b in [Block(1, 2), Block(2, 1)]
344+
a[b] = randn(elt, size(a[b]))
345+
end
338346
b = a[Block(2):Block(2), Block(1):Block(2)]
339347
@test block_nstored(b) == 1
340348
@test b == Array(a)[3:5, 1:end]
349+
350+
a = BlockSparseArray{elt}(undef, ([2, 3, 4], [2, 3, 4]))
351+
# TODO: Define `block_diagindices`.
352+
@views for b in [Block(1, 1), Block(2, 2), Block(3, 3)]
353+
a[b] = randn(elt, size(a[b]))
354+
end
355+
for (I1, I2) in (
356+
(mortar([Block(2)[2:3], Block(3)[1:3]]), mortar([Block(2)[2:3], Block(3)[2:3]])),
357+
([Block(2)[2:3], Block(3)[1:3]], [Block(2)[2:3], Block(3)[2:3]]),
358+
)
359+
for b in (a[I1, I2], @view(a[I1, I2]))
360+
# TODO: Rename `block_stored_length`.
361+
@test block_nstored(b) == 2
362+
@test b[Block(1, 1)] == a[Block(2, 2)[2:3, 2:3]]
363+
@test b[Block(2, 2)] == a[Block(3, 3)[1:3, 2:3]]
364+
end
365+
end
366+
367+
a = BlockSparseArray{elt}(undef, ([3, 3], [3, 3]))
368+
# TODO: Define `block_diagindices`.
369+
@views for b in [Block(1, 1), Block(2, 2)]
370+
a[b] = randn(elt, size(a[b]))
371+
end
372+
I = mortar([Block(1)[1:2], Block(2)[1:2]])
373+
b = a[:, I]
374+
@test b[Block(1, 1)] == a[Block(1, 1)][:, 1:2]
375+
@test b[Block(2, 1)] == a[Block(2, 1)][:, 1:2]
376+
@test b[Block(1, 2)] == a[Block(1, 2)][:, 1:2]
377+
@test b[Block(2, 2)] == a[Block(2, 2)][:, 1:2]
378+
@test blocklengths.(axes(b)) == ([3, 3], [2, 2])
379+
# TODO: Rename `block_stored_length`.
380+
@test blocksize(b) == (2, 2)
381+
@test block_nstored(b) == 2
382+
383+
a = BlockSparseArray{elt}(undef, ([2, 3], [3, 4]))
384+
@views for b in [Block(1, 2), Block(2, 1)]
385+
a[b] = randn(elt, size(a[b]))
386+
end
387+
@test isassigned(a, 1, 1)
388+
@test isassigned(a, 5, 7)
389+
@test !isassigned(a, 0, 1)
390+
@test !isassigned(a, 5, 8)
391+
@test isassigned(a, Block(1), Block(1))
392+
@test isassigned(a, Block(2), Block(2))
393+
@test !isassigned(a, Block(1), Block(0))
394+
@test !isassigned(a, Block(3), Block(2))
395+
@test isassigned(a, Block(1, 1))
396+
@test isassigned(a, Block(2, 2))
397+
@test !isassigned(a, Block(1, 0))
398+
@test !isassigned(a, Block(3, 2))
399+
@test isassigned(a, Block(1)[1], Block(1)[1])
400+
@test isassigned(a, Block(2)[3], Block(2)[4])
401+
@test !isassigned(a, Block(1)[0], Block(1)[1])
402+
@test !isassigned(a, Block(2)[3], Block(2)[5])
403+
@test !isassigned(a, Block(1)[1], Block(0)[1])
404+
@test !isassigned(a, Block(3)[3], Block(2)[4])
341405
end
342406
@testset "LinearAlgebra" begin
343407
a1 = BlockSparseArray{elt}([2, 3], [2, 3])

NDTensors/src/lib/SparseArrayInterface/src/sparsearrayinterface/indexing.jl

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,11 @@ function sparse_setindex!(a::AbstractArray, value, I::NotStoredIndex)
160160
end
161161

162162
# isassigned
163-
function sparse_isassigned(a::AbstractArray, I::Integer...)
164-
return sparse_isassigned(a, CartesianIndex(I))
163+
function sparse_isassigned(a::AbstractArray{<:Any,N}, I::CartesianIndex{N}) where {N}
164+
return sparse_isassigned(a, Tuple(I)...)
165165
end
166-
sparse_isassigned(a::AbstractArray, I::NotStoredIndex) = true
167-
sparse_isassigned(a::AbstractArray, I::StoredIndex) = sparse_isassigned(a, StorageIndex(I))
168-
function sparse_isassigned(a::AbstractArray, I::StorageIndex)
169-
return isassigned(sparse_storage(a), index(I))
170-
end
171-
function sparse_isassigned(a::AbstractArray, I::CartesianIndex)
172-
return sparse_isassigned(a, storage_index(a, I))
166+
function sparse_isassigned(a::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
167+
return all(dim -> I[dim] axes(a, dim), 1:ndims(a))
173168
end
174169

175170
# A set of indices into the storage of the sparse array.

NDTensors/src/lib/SparseArrayInterface/test/test_abstractsparsearray.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ using Test: @test, @testset
2121
for I in eachindex(a)
2222
@test iszero(a)
2323
end
24+
for I in CartesianIndices(a)
25+
@test isassigned(a, Tuple(I)...)
26+
@test isassigned(a, I)
27+
end
28+
@test !isassigned(a, 0, 1)
29+
@test !isassigned(a, CartesianIndex(0, 1))
30+
@test !isassigned(a, 1, 4)
31+
@test !isassigned(a, CartesianIndex(1, 4))
2432

2533
a = SparseArray{elt}(2, 3)
2634
fill!(a, 0)
@@ -60,6 +68,14 @@ using Test: @test, @testset
6068
@test iszero(a[I])
6169
end
6270
end
71+
for I in CartesianIndices(a)
72+
@test isassigned(a, Tuple(I)...)
73+
@test isassigned(a, I)
74+
end
75+
@test !isassigned(a, 0, 1)
76+
@test !isassigned(a, CartesianIndex(0, 1))
77+
@test !isassigned(a, 1, 4)
78+
@test !isassigned(a, CartesianIndex(1, 4))
6379

6480
a = SparseArray{elt}(2, 3)
6581
a[1, 2] = 12

0 commit comments

Comments
 (0)