BlockArrays
Creating BlockArray
s from an array
An AbstractArray
can be repacked into a BlockArray
with BlockArray(array, block_sizes...)
. The block sizes are each an AbstractVector{Int}
which determines the size of the blocks in that dimension (so the sum of block_sizes
in every dimension must match the size of array
in that dimension).
julia> BlockArray(Array(reshape(1:16, 4, 4)), [2,2], [1,1,2])
2×3-blocked 4×4 BlockMatrix{Int64}:
1 │ 5 │ 9 13
2 │ 6 │ 10 14
───┼─────┼────────
3 │ 7 │ 11 15
4 │ 8 │ 12 16
julia> S = spzeros(4,5); S[1,2] = S[4,3] = 1;
julia> block_array_sparse = BlockArray(S, [1,3], [2,3])
2×2-blocked 4×5 BlockMatrix{Float64, Matrix{SparseMatrixCSC{Float64, Int64}}, Tuple{BlockedOneTo{Int64, Vector{Int64}}, BlockedOneTo{Int64, Vector{Int64}}}}:
⋅ 1.0 │ ⋅ ⋅ ⋅
──────────┼───────────────
⋅ ⋅ │ ⋅ ⋅ ⋅
⋅ ⋅ │ ⋅ ⋅ ⋅
⋅ ⋅ │ 1.0 ⋅ ⋅
Creating uninitialized BlockArray
s
A block array can be created with uninitialized values (but initialized blocks) using the BlockArray{T}(undef, block_sizes)
function. The block_sizes
are each an AbstractVector{Int}
which determines the size of the blocks in that dimension. We here create a block matrix of Float32
s:
julia> BlockArray{Float32}(undef, [1,2,1], [1,1,1])
3×3-blocked 4×3 BlockMatrix{Float32}:
-2.15145e-35 │ 1.4013e-45 │ -1.77199e-35
──────────────┼────────────────┼──────────────
1.4013e-45 │ -1.77199e-35 │ -1.72473e-34
1.4013e-45 │ 4.57202e-41 │ 4.57202e-41
──────────────┼────────────────┼──────────────
0.0 │ -1.36568e-33 │ -1.72473e-34
We can also any other user defined array type that supports similar
.
Creating BlockArrays
with uninitialized blocks.
A BlockArray
can be created with the blocks left uninitialized using the BlockArray(undef_blocks[, block_type], block_sizes...)
function. We here create a [1,2]×[3,2]
block matrix of Float32
s:
julia> BlockArray{Float32}(undef_blocks, [1,2], [3,2])
2×2-blocked 3×5 BlockMatrix{Float32}:
#undef #undef #undef │ #undef #undef
────────────────────────┼────────────────
#undef #undef #undef │ #undef #undef
#undef #undef #undef │ #undef #undef
The block_type
should be an array type. It specifies the internal block type, which defaults to an Array
of the according dimension. We can also use a SparseVector
or any other user defined array type:
julia> BlockArray(undef_blocks, SparseVector{Float64, Int}, [1,2])
2-blocked 3-element BlockVector{Float64, Vector{SparseVector{Float64, Int64}}, Tuple{BlockedOneTo{Int64, Vector{Int64}}}}:
#undef
──────
#undef
#undef
Note that accessing an undefined block will throw an "access to undefined reference"-error! If you create an array with undefined blocks, you have to initialize it block-wise); whole-array functions like fill!
will not work:
julia> fill!(BlockArray{Float32}(undef_blocks, [1,2], [3,2]), 0)
ERROR: UndefRefError: access to undefined reference
Setting and getting blocks and values
A block can be set by block_array[Block(i...)] = v
. The indexing may equivalently be carried out as block_array[Block.(i)...]
.
julia> block_array = BlockArray{Float64}(undef_blocks, [1,2], [2,2])
2×2-blocked 3×4 BlockMatrix{Float64}:
#undef #undef │ #undef #undef
────────────────┼────────────────
#undef #undef │ #undef #undef
#undef #undef │ #undef #undef
julia> block_array[Block(2,1)] = reshape([1:4;], 2, 2);
julia> block_array[Block(1),Block(1)] = [1 2];
julia> block_array
2×2-blocked 3×4 BlockMatrix{Float64}:
1.0 2.0 │ #undef #undef
──────────┼────────────────
1.0 3.0 │ #undef #undef
2.0 4.0 │ #undef #undef
Note that this will "take ownership" of the passed in array, that is, no copy is made.
A block can be retrieved with view(block_array, Block(i...))
, or if a copy is desired, block_array[Block(i...)]
:
julia> view(block_array, Block(1, 1))
1×2 Matrix{Float64}:
1.0 2.0
julia> block_array[Block(1, 1)] # makes a copy
1×2 Matrix{Float64}:
1.0 2.0
julia> block_array[Block(1), Block(1)] # equivalent to above
1×2 Matrix{Float64}:
1.0 2.0
For setting and getting a single scalar element, the usual setindex!
and getindex
are available.
julia> block_array[1, 2]
2.0
Views of blocks
To view and modify blocks of BlockArray
use the view
syntax.
julia> A = BlockArray(ones(6), 1:3);
julia> view(A, Block(2))
2-element Vector{Float64}:
1.0
1.0
julia> view(A, Block(2)) .= [3,4]; A[Block(2)]
2-element Vector{Float64}:
3.0
4.0
julia> view(A, Block.(1:2))
3-element view(::BlockVector{Float64, Vector{Vector{Float64}}, Tuple{BlockedOneTo{Int64, ArrayLayouts.RangeCumsum{Int64, UnitRange{Int64}}}}}, BlockSlice(BlockRange(1:2),1:1:3)) with eltype Float64 with indices BlockedOneTo([1, 3]):
1.0
3.0
4.0
Converting between BlockArray
and normal arrays
An array can be repacked into a BlockArray
with BlockArray(array, block_sizes...)
:
julia> S = spzeros(4,5); S[1,2] = S[4,3] = 1;
julia> block_array_sparse = BlockArray(S, [1,3], [2,3])
2×2-blocked 4×5 BlockMatrix{Float64, Matrix{SparseMatrixCSC{Float64, Int64}}, Tuple{BlockedOneTo{Int64, Vector{Int64}}, BlockedOneTo{Int64, Vector{Int64}}}}:
⋅ 1.0 │ ⋅ ⋅ ⋅
──────────┼───────────────
⋅ ⋅ │ ⋅ ⋅ ⋅
⋅ ⋅ │ ⋅ ⋅ ⋅
⋅ ⋅ │ 1.0 ⋅ ⋅
To get back the underlying sparse array, use sparse
:
julia> sparse(block_array_sparse)
4×5 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
⋅ 1.0 ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ 1.0 ⋅ ⋅
To get a dense array, use Array
:
julia> Array(block_array_sparse)
4×5 Matrix{Float64}:
0.0 1.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 1.0 0.0 0.0