Skip to content

Commit b1db5ee

Browse files
authored
export and test BlockIndex (#16)
1 parent d3aa589 commit b1db5ee

File tree

9 files changed

+74
-11
lines changed

9 files changed

+74
-11
lines changed

docs/src/lib/internals.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ Pages = ["internals.md"]
1919
## Internals
2020

2121
```@docs
22-
BlockIndex
2322
blockindex2global
2423
global2blockindex
2524
```

docs/src/lib/public.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This sections defines the functions a subtype of `AbstractBlockArray` should def
2929
AbstractBlockArray
3030
BlockBoundsError
3131
Block
32+
BlockIndex
3233
nblocks
3334
blocksize
3435
getblock

docs/src/man/pseudoblockarrays.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ a direct solver using `full`.
1919

2020
Creating a `PseudoBlockArray` works in the same way as a `BlockArray`.
2121

22-
```jldoctest
22+
```jldoctest A
2323
julia> pseudo = PseudoBlockArray(rand(3,3), [1,2], [2,1])
2424
2×2-blocked 3×3 BlockArrays.PseudoBlockArray{Float64,2,Array{Float64,2}}:
2525
0.590845 0.460085 │ 0.200586
@@ -35,7 +35,7 @@ This "takes ownership" of the passed in array so no copy of the array is made.
3535
Setting and getting blocks uses the same API as `BlockArrays`. The difference here is that setting a block will update the block in place and getting a block
3636
will extract a copy of the block and return it. For `PseudoBlockArrays` there is a mutating block getter called `getblock!` which updates a passed in array to avoid a copy:
3737

38-
```jldoctest
38+
```jldoctest A
3939
julia> A = zeros(2,2)
4040
2×2 Array{Float64,2}:
4141
0.0 0.0
@@ -49,4 +49,11 @@ julia> A
4949
0.566237 0.854147
5050
```
5151

52+
It is sometimes convenient to access an index in a certain block. We could of course write this as `A[Block(I,J)][i,j]` but the problem is that `A[Block(I,J)]` allocates its output so this type of indexing will be inefficient. Instead, it is possible to use the `A[BlockIndex((I,J), (i,j))]` indexing. Using the same block matrix `A` as above:
53+
54+
```jldoctest A
55+
julia> pseudo[BlockIndex((2,1), (2,2))]
56+
0.8541465903790502
57+
```
58+
5259
The underlying array is accessed with `Array` just like for `BlockArray`.

src/BlockArrays.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module BlockArrays
44

55
# AbstractBlockArray interface exports
66
export AbstractBlockArray, AbstractBlockMatrix, AbstractBlockVector, AbstractBlockVecOrMat
7-
export Block, getblock, getblock!, setblock!, nblocks, blocksize, blockcheckbounds, BlockBoundsError
7+
export Block, getblock, getblock!, setblock!, nblocks, blocksize, blockcheckbounds, BlockBoundsError, BlockIndex
88

99
export BlockArray, BlockMatrix, BlockVector, BlockVecOrMat
1010
export PseudoBlockArray, PseudoBlockMatrix, PseudoBlockVector, PseudoBlockVecOrMat

src/blockarray.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ end
148148
return block_arr
149149
end
150150

151-
@inline function Base.setindex!{T,N}(block_array::BlockArray{T, N}, v, block_index::BlockIndex{N})
151+
@propagate_inbounds function Base.setindex!{T,N}(block_array::BlockArray{T, N}, v, block_index::BlockIndex{N})
152152
getblock(block_array, block_index.I...)[block_index.α...] = v
153153
end
154154

src/blockindices.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,46 @@
33
44
A `BlockIndex` is an index which stores a global index in two parts: the block
55
and the offset index into the block.
6+
7+
It can be used to index into `BlockArrays` in the following manner:
8+
9+
```jldoctest
10+
julia> arr = Array(reshape(1:25, (5,5)));
11+
12+
julia> a = PseudoBlockArray(arr, [3,2], [1,4])
13+
2×2-blocked 5×5 BlockArrays.PseudoBlockArray{Int64,2,Array{Int64,2}}:
14+
1 │ 6 11 16 21
15+
2 │ 7 12 17 22
16+
3 │ 8 13 18 23
17+
───┼────────────────
18+
4 │ 9 14 19 24
19+
5 │ 10 15 20 25
20+
21+
julia> a[BlockIndex((1,2), (1,2))]
22+
11
23+
24+
julia> a[BlockIndex((2,2), (2,3))]
25+
20
26+
```
627
"""
728
immutable BlockIndex{N}
829
I::NTuple{N, Int}
930
α::NTuple{N, Int}
1031
end
1132

33+
@inline BlockIndex(a::Int, b::Int) = BlockIndex((a,), (b,))
34+
@inline BlockIndex(a::NTuple, b::Int) = BlockIndex(a, (b,))
35+
@inline BlockIndex(a::Int, b::NTuple) = BlockIndex((a,), b)
36+
37+
@generated function BlockIndex{M, N}(I::NTuple{N, Int}, α::NTuple{M, Int})
38+
@assert M < N
39+
α_ex = Expr(:tuple, [k <= M ? :(α[$k]) : :(1) for k = 1:N]...)
40+
return quote
41+
$Expr(:meta, :inline)
42+
@inbounds α2 = $α_ex
43+
BlockIndex(I, α2)
44+
end
45+
end
1246

1347
"""
1448
global2blockindex{N}(block_sizes::BlockSizes{N}, inds...) -> BlockIndex{N}
@@ -20,6 +54,7 @@ Converts from global indices `inds` to a `BlockIndex`.
2054
I_ex = Expr(:tuple, [:(block_index[$k][1]) for k = 1:N]...)
2155
α_ex = Expr(:tuple, [:(block_index[$k][2]) for k = 1:N]...)
2256
return quote
57+
$Expr(:meta, :inline)
2358
@inbounds block_index = $block_index_ex
2459
@inbounds I = $I_ex
2560
@inbounds α = $α_ex
@@ -35,6 +70,7 @@ Converts from a block index to a tuple containing the global indices
3570
@generated function blockindex2global{N}(block_sizes::BlockSizes{N}, block_index::BlockIndex{N})
3671
ex = Expr(:tuple, [:(block_sizes[$k, block_index.I[$k]] + block_index.α[$k] - 1) for k = 1:N]...)
3772
return quote
73+
$Expr(:meta, :inline)
3874
@inbounds v = $ex
3975
return $ex
4076
end

src/blocksizes.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ end
9393
#start_indices_ex = Expr(:tuple, [:(1 + _cumsum(block_sizes[$i], block_index[$i]-1)) for i=1:N]...)
9494
indices_ex = Expr(:tuple, [:(block_sizes[$i, block_index[$i]]:block_sizes[$i, block_index[$i] + 1] - 1) for i = 1:N]...)
9595
return quote
96+
$Expr(:meta, :inline)
9697
@inbounds inds = $indices_ex
9798
return inds
9899
end

src/pseudo_blockarray.jl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ end
9898
# Indexing #
9999
############
100100

101+
@inline function Base.getindex{T, N}(block_arr::PseudoBlockArray{T,N}, blockindex::BlockIndex{N})
102+
I = blockindex2global(block_arr.block_sizes, blockindex)
103+
@boundscheck checkbounds(block_arr.blocks, I...)
104+
@inbounds v = block_arr.blocks[I...]
105+
return v
106+
end
101107

102108
@inline function getblock{T,N}(block_arr::PseudoBlockArray{T,N}, block::Vararg{Int, N})
103109
range = globalrange(block_arr.block_sizes, block)
@@ -129,6 +135,13 @@ end
129135
end
130136
end
131137

138+
@inline function Base.setindex!{T, N}(block_arr::PseudoBlockArray{T,N}, v, blockindex::BlockIndex{N})
139+
I = blockindex2global(block_arr.block_sizes, blockindex)
140+
@boundscheck checkbounds(block_arr.blocks, I...)
141+
@inbounds block_arr.blocks[I...] = v
142+
return block_arr
143+
end
144+
132145
function _check_setblock!{T, N}(blockrange, x, block_arr::PseudoBlockArray{T,N}, block::NTuple{N, Int})
133146
blocksizes = blocksize(block_arr, block...)
134147
for i in 1:N
@@ -138,7 +151,6 @@ function _check_setblock!{T, N}(blockrange, x, block_arr::PseudoBlockArray{T,N},
138151
end
139152
end
140153

141-
142154
@generated function setblock!{T, N}(block_arr::PseudoBlockArray{T, N}, x, block::Vararg{Int, N})
143155
return quote
144156
blockrange = globalrange(block_arr.block_sizes, block)
@@ -153,6 +165,8 @@ end
153165
end
154166
end
155167

168+
169+
156170
########
157171
# Misc #
158172
########

test/test_blockarrays.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
BA_1 = BlockArray(Vector{Float64}, [1,2,3])
44
a_1 = rand(2)
55
BA_1[Block(2)] = a_1
6+
@test BA_1[BlockIndex(2, 1)] == a_1[1]
7+
@test BA_1[BlockIndex(2, 2)] == a_1[2]
68
@test BA_1[Block(2)] == a_1
79
@test BA_1[2] == a_1[1]
810
@test_throws DimensionMismatch BA_1[Block(3)] = rand(4)
@@ -23,12 +25,13 @@ end
2325
for BlockType in (BlockArray, PseudoBlockArray)
2426
a_1 = rand(6)
2527
BA_1 = BlockType(a_1, [1,2,3])
26-
@test full(BA_1) == a_1
28+
@test Array(BA_1) == a_1
2729
@test nblocks(BA_1) == (3,)
2830
@test nblocks(BA_1,1) == 3
2931
@test eltype(similar(BA_1, Float32)) == Float32
3032
q = rand(1)
3133
BA_1[Block(1)] = q
34+
BA_1[BlockIndex(3, 2)] = a_1[5]
3235
@test BA_1[Block(1)] == q
3336
if BlockType == PseudoBlockArray
3437
q2 = zeros(q)
@@ -47,17 +50,18 @@ end
4750

4851
a_1_sparse = sprand(6, 0.9)
4952
BA_1_sparse = BlockType(a_1_sparse, [1,2,3])
50-
@test full(BA_1_sparse) == a_1_sparse
53+
@test Array(BA_1_sparse) == a_1_sparse
5154
BA_1_sparse[4] = 3.0
5255
@test BA_1_sparse[4] == 3.0
5356

5457

5558
a_2 = rand(3, 7)
5659
BA_2 = BlockType(a_2, [1,2], [3,4])
57-
@test full(BA_2) == a_2
60+
@test Array(BA_2) == a_2
5861
@test nblocks(BA_2) == (2,2)
5962
@test nblocks(BA_2, 1) == 2
6063
@test nblocks(BA_2, 2, 1) == (2, 2)
64+
BA_2[BlockIndex((2,1), (2,2))] = a_2[3,2]
6165
@test eltype(similar(BA_2, Float32)) == Float32
6266
q = rand(1,4)
6367
BA_2[Block(1,2)] = q
@@ -77,17 +81,18 @@ end
7781

7882
a_2_sparse = sprand(3, 7, 0.9)
7983
BA_2_sparse = BlockType(a_2_sparse, [1,2], [3,4])
80-
@test full(BA_2_sparse) == a_2_sparse
84+
@test Array(BA_2_sparse) == a_2_sparse
8185
BA_2_sparse[1,2] = 3.0
8286
@test BA_2_sparse[1,2] == 3.0
8387

8488
a_3 = rand(3, 7,4)
8589
BA_3 = BlockType(a_3, [1,2], [3,4], [1,2,1])
86-
@test full(BA_3) == a_3
90+
@test Array(BA_3) == a_3
8791
@test nblocks(BA_3) == (2,2,3)
8892
@test nblocks(BA_3, 1) == 2
8993
@test nblocks(BA_3, 3, 1) == (3, 2)
9094
@test nblocks(BA_3, 3) == 3
95+
BA_3[BlockIndex((1,1,1), (1,1,1))] = a_3[1,1,1]
9196
@test eltype(similar(BA_3, Float32)) == Float32
9297
q = rand(1,4,2)
9398
BA_3[Block(1,2,2)] = q

0 commit comments

Comments
 (0)