Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create constructor for creating allocated BlockArrays #39

Merged
merged 7 commits into from
Dec 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion REQUIRE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
julia 0.6
Compat 0.30.0
Compat 0.38.0
Copy link
Member

@fredrikekre fredrikekre Dec 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compat 0.39

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't depend on anything in Compat 0.39 that's not in Compat 0.38, so I think this should be left.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compat 0.38 is broken. Please update to 0.39.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote this and then I merged 20 seconds later. Oh well, will update on master.

2 changes: 2 additions & 0 deletions docs/src/lib/public.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ blockcheckbounds

```@docs
BlockArray
uninitialized_blocks
UninitializedBlocks
```


Expand Down
33 changes: 24 additions & 9 deletions docs/src/man/blockarrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,45 @@ DocTestSetup = quote
end
```

## Creating uninitialized `BlockArrays`.

A `BlockArray` can be created with the blocks left uninitialized using the `BlockArray(block_type, block_sizes...)` function.
The `block_type` should be an array type, it could for example be `Matrix{Float64}`. The block sizes are each a `Vector{Int}` which determines the size of the blocks in that dimension. We here create a `[1,2]×[3,2]` block matrix of `Float32`s:
## Creating uninitialized `BlockArrays`

A block array can be created with initialized blocks using the `BlockArray{T}(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 `[1,2]×[3,2]` block matrix of `Float32`s:
```julia
julia> BlockArray{Float32}(uninitialized, [1,2], [3,2])
2×2-blocked 3×5 BlockArrays.BlockArray{Float32,2,Array{Float32,2}}:
9.39116f-26 1.4013f-45 3.34245f-21 │ 9.39064f-26 1.4013f-45
───────────────────────────────────────┼──────────────────────────
3.28434f-21 9.37645f-26 3.28436f-21 │ 8.05301f-24 9.39077f-26
1.4013f-45 1.4013f-45 1.4013f-45 │ 1.4013f-45 1.4013f-45
```
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(uninitialized, block_type, block_sizes...)` function.
The `block_type` should be an array type, it could for example be `Matrix{Float64}`. The block sizes are each an `AbstractVector{Int}` which determines the size of the blocks in that dimension. We here create a `[1,2]×[3,2]` block matrix of `Float32`s:

```jldoctest
julia> BlockArray(Matrix{Float32}, [1,2], [3,2])
julia> BlockArray{Float32}(uninitialized_blocks, [1,2], [3,2])
2×2-blocked 3×5 BlockArrays.BlockArray{Float32,2,Array{Float32,2}}:
#undef #undef #undef │ #undef #undef
------------------------┼----------------
#undef #undef #undef │ #undef #undef
#undef #undef #undef │ #undef #undef
```

We can also use a `SparseVector` or any other user defined array type:
We can also use a `SparseVector` or any other user defined array type by
specifying it as the second argument:

```jl
julia> BlockArray(SparseVector{Float64, Int}, [1,2])
julia> BlockArray(uninitialized_blocks, SparseVector{Float64, Int}, [1,2])
2-blocked 3-element BlockArrays.BlockArray{Float64,1,SparseVector{Float64,Int64}}:
#undef
------
#undef
#undef
julia> BlockArray(SparseVector{Float64, Int}, [1,2])
```

Note that accessing an undefined block will throw an "access to undefined reference"-error.
Expand All @@ -41,7 +56,7 @@ An alternative syntax for this is `block_array[Block(i...)] = v` or
`block_array[Block.(i)...]`.

```jldoctest
julia> block_array = BlockArray(Matrix{Float64}, [1,2], [2,2])
julia> block_array = BlockArray{Float64}(unitialized_blocks, [1,2], [2,2])
2×2-blocked 3×4 BlockArrays.BlockArray{Float64,2,Array{Float64,2}}:
#undef #undef │ #undef #undef
----------------┼----------------
Expand Down Expand Up @@ -109,7 +124,7 @@ julia> view(A, Block(2)) .= [3,4]; A[Block(2)]

## Converting between `BlockArray` and normal arrays

An array can be repacked into a `BlockArray` with`BlockArray(array, block_sizes...)`:
An array can be repacked into a `BlockArray` with `BlockArray(array, block_sizes...)`:

```jl
julia> block_array_sparse = BlockArray(sprand(4, 5, 0.7), [1,3], [2,3])
Expand Down
15 changes: 15 additions & 0 deletions docs/src/man/pseudoblockarrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ julia> pseudo = PseudoBlockArray(rand(3,3), [1,2], [2,1])

This "takes ownership" of the passed in array so no copy of the array is made.


## Creating initialized `BlockArrays`

A block array can be created with uninitialized entries using the `BlockArray{T}(uninitialized, 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 `[1,2]×[3,2]` block matrix of `Float32`s:
```julia
julia> PseudoBlockArray{Float32}(uninitialized, [1,2], [3,2])
2×2-blocked 3×5 BlockArrays.BlockArray{Float32,2,Array{Float32,2}}:
9.39116f-26 1.4013f-45 3.34245f-21 │ 9.39064f-26 1.4013f-45
───────────────────────────────────────┼──────────────────────────
3.28434f-21 9.37645f-26 3.28436f-21 │ 8.05301f-24 9.39077f-26
1.4013f-45 1.4013f-45 1.4013f-45 │ 1.4013f-45 1.4013f-45
```
We can also any other user defined array type that supports `similar`.

## Setting and getting blocks and values

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
Expand Down
9 changes: 6 additions & 3 deletions src/BlockArrays.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
__precompile__()

module BlockArrays
using Base.Cartesian
using Compat

# AbstractBlockArray interface exports
export AbstractBlockArray, AbstractBlockMatrix, AbstractBlockVector, AbstractBlockVecOrMat
Expand All @@ -10,13 +12,14 @@ export BlockRange
export BlockArray, BlockMatrix, BlockVector, BlockVecOrMat
export PseudoBlockArray, PseudoBlockMatrix, PseudoBlockVector, PseudoBlockVecOrMat

export uninitialized_blocks, UninitializedBlocks, uninitialized, Uninitialized

import Base: @propagate_inbounds, Array, to_indices, to_index, indices,
unsafe_indices, indices1, first, last, size, length, unsafe_length,
getindex, show, start, next, done, @_inline_meta, _maybetail, tail,
colon, broadcast, eltype, iteratorsize

using Base.Cartesian
using Compat



include("abstractblockarray.jl")
Expand All @@ -29,6 +32,6 @@ include("blockrange.jl")
include("views.jl")
include("convert.jl")
include("show.jl")

include("deprecate.jl")

end # module
154 changes: 126 additions & 28 deletions src/blockarray.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,55 @@
# Note: Functions surrounded by a comment blocks are there because `Vararg` is still allocating.
# When Vararg is fast enough, they can simply be removed.


#######################
# UninitializedBlocks #
#######################

"""
UninitializedBlocks

Singleton type used in block array initialization, indicating the
array-constructor-caller would like an uninitialized block array. See also
uninitialized_blocks (@ref), an alias for UninitializedBlocks().

Examples
≡≡≡≡≡≡≡≡≡≡

julia> BlockArray(uninitialized_blocks, Matrix{Float32}, [1,2], [3,2])
2×2-blocked 3×5 BlockArrays.BlockArray{Float32,2,Array{Float32,2}}:
#undef #undef #undef │ #undef #undef
------------------------┼----------------
#undef #undef #undef │ #undef #undef
#undef #undef #undef │ #undef #undef
"""
struct UninitializedBlocks end

"""
uninitialized_blocks

Alias for UninitializedBlocks(), which constructs an instance of the singleton
type UninitializedBlocks (@ref), used in block array initialization to indicate the
array-constructor-caller would like an uninitialized block array.

Examples
≡≡≡≡≡≡≡≡≡≡

julia> BlockArray(uninitialized_blocks, Matrix{Float32}, [1,2], [3,2])
2×2-blocked 3×5 BlockArrays.BlockArray{Float32,2,Array{Float32,2}}:
#undef #undef #undef │ #undef #undef
------------------------┼----------------
#undef #undef #undef │ #undef #undef
#undef #undef #undef │ #undef #undef
"""
const uninitialized_blocks = UninitializedBlocks()

##############
# BlockArray #
##############

function _BlockArray end

"""
BlockArray{T, N, R <: AbstractArray{T, N}} <: AbstractBlockArray{T, N}

Expand All @@ -16,15 +61,15 @@ In the type definition, `R` defines the array type that each block has, for exam
struct BlockArray{T, N, R <: AbstractArray{T, N}} <: AbstractBlockArray{T, N}
blocks::Array{R, N}
block_sizes::BlockSizes{N}
end

# Auxilary outer constructors
function BlockArray(blocks::Array{R, N}, block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}}
return BlockArray{T, N, R}(blocks, block_sizes)
global function _BlockArray(blocks::Array{R, N}, block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}}
new{T, N, R}(blocks, block_sizes)
end
end

function BlockArray(blocks::Array{R, N}, block_sizes::Vararg{Vector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
return BlockArray{T, N, R}(blocks, BlockSizes(block_sizes...))
# Auxilary outer constructors
function _BlockArray(blocks::Array{R, N}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
return _BlockArray(blocks, BlockSizes(block_sizes...))
end

const BlockMatrix{T, R <: AbstractMatrix{T}} = BlockArray{T, 2, R}
Expand All @@ -35,11 +80,25 @@ const BlockVecOrMat{T, R} = Union{BlockMatrix{T, R}, BlockVector{T, R}}
# Constructors #
################

@inline function _BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
_BlockArray(R, BlockSizes(block_sizes...))
end

function _BlockArray(::Type{R}, block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}}
n_blocks = nblocks(block_sizes)
blocks = Array{R, N}(uninitialized, n_blocks)
_BlockArray(blocks, block_sizes)
end

@inline function uninitialized_blocks_BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
_BlockArray(R, block_sizes...)
end

"""
Constructs a `BlockArray` with uninitialized blocks from a block type `R` with sizes defind by `block_sizes`.

```jldoctest
julia> BlockArray(Matrix{Float64}, [1,3], [2,2])
julia> BlockArray(uninitialized_blocks, Matrix{Float64}, [1,3], [2,2])
2×2-blocked 4×4 BlockArrays.BlockArray{Float64,2,Array{Float64,2}}:
#undef │ #undef #undef #undef │
--------┼--------------------------┼
Expand All @@ -49,17 +108,66 @@ julia> BlockArray(Matrix{Float64}, [1,3], [2,2])
#undef │ #undef #undef #undef │
```
"""
@inline function BlockArray(::Type{R}, block_sizes::Vararg{Vector{Int}, N}) where {T,N,R <: AbstractArray{T, N}}
BlockArray(R, BlockSizes(block_sizes...))
@inline function BlockArray(::UninitializedBlocks, ::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
uninitialized_blocks_BlockArray(R, block_sizes...)
end

function BlockArray(::Type{R}, block_sizes::BlockSizes{N}) where {T,N,R <: AbstractArray{T, N}}
n_blocks = nblocks(block_sizes)
blocks = Array{R, N}(n_blocks)
BlockArray{T,N,R}(blocks, block_sizes)
@inline function BlockArray{T}(::UninitializedBlocks, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N}
BlockArray(uninitialized_blocks, Array{T,N}, block_sizes...)
end

@inline function BlockArray{T,N}(::UninitializedBlocks, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N}
BlockArray(uninitialized_blocks, Array{T,N}, block_sizes...)
end

@inline function BlockArray{T,N,R}(::UninitializedBlocks, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
BlockArray(uninitialized_blocks, R, block_sizes...)
end

function BlockArray(arr::AbstractArray{T, N}, block_sizes::Vararg{Vector{Int}, N}) where {T,N}


@generated function initialized_blocks_BlockArray(::Type{R}, block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}}
return quote
block_arr = _BlockArray(R, block_sizes)
@nloops $N i i->(1:nblocks(block_sizes, i)) begin
block_index = @ntuple $N i
setblock!(block_arr, similar(R, blocksize(block_sizes, block_index)), block_index...)
end

return block_arr
end
end


function initialized_blocks_BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
initialized_blocks_BlockArray(R, BlockSizes(block_sizes...))
end

@inline function BlockArray{T}(::Uninitialized, block_sizes::BlockSizes{N}) where {T, N}
initialized_blocks_BlockArray(Array{T, N}, block_sizes)
end

@inline function BlockArray{T, N}(::Uninitialized, block_sizes::BlockSizes{N}) where {T, N}
initialized_blocks_BlockArray(Array{T, N}, block_sizes)
end

@inline function BlockArray{T, N, R}(::Uninitialized, block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}}
initialized_blocks_BlockArray(R, block_sizes)
end

@inline function BlockArray{T}(::Uninitialized, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N}
initialized_blocks_BlockArray(Array{T, N}, block_sizes...)
end

@inline function BlockArray{T, N}(::Uninitialized, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N}
initialized_blocks_BlockArray(Array{T, N}, block_sizes...)
end

@inline function BlockArray{T, N, R}(::Uninitialized, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
initialized_blocks_BlockArray(R, block_sizes...)
end

function BlockArray(arr::AbstractArray{T, N}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T,N}
for i in 1:N
if sum(block_sizes[i]) != size(arr, i)
throw(DimensionMismatch("block size for dimension $i: $(block_sizes[i]) does not sum to the array size: $(size(arr, i))"))
Expand All @@ -70,7 +178,7 @@ end

@generated function BlockArray(arr::AbstractArray{T, N}, block_sizes::BlockSizes{N}) where {T,N}
return quote
block_arr = BlockArray(typeof(arr), block_sizes)
block_arr = _BlockArray(typeof(arr), block_sizes)
@nloops $N i i->(1:nblocks(block_sizes, i)) begin
block_index = @ntuple $N i
indices = globalrange(block_sizes, block_index)
Expand All @@ -81,13 +189,6 @@ end
end
end


BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T,N,R <: AbstractArray{T, N}} =
BlockArray(R, Vector{Int}.(block_sizes)...)

BlockArray(arr::AbstractArray{T, N}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T,N} =
BlockArray(arr, Vector{Int}.(block_sizes)...)

################################
# AbstractBlockArray Interface #
################################
Expand All @@ -114,14 +215,11 @@ end
###########################

@inline function Base.similar(block_array::BlockArray{T,N}, ::Type{T2}) where {T,N,T2}
BlockArray(similar(block_array.blocks, Array{T2, N}), copy(block_array.block_sizes))
_BlockArray(similar(block_array.blocks, Array{T2, N}), copy(block_array.block_sizes))
end

@generated function Base.size(arr::BlockArray{T,N}) where {T,N}
exp = Expr(:tuple, [:(arr.block_sizes[$i][end] - 1) for i in 1:N]...)
return quote
@inbounds return $exp
end
@inline function Base.size(arr::BlockArray{T,N}) where {T,N}
size(arr.block_sizes)
end

@inline function Base.getindex(block_arr::BlockArray{T, N}, i::Vararg{Int, N}) where {T,N}
Expand Down
8 changes: 8 additions & 0 deletions src/blocksizes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ end
return exp
end

# Gives the total sizes
@generated function Base.size(block_sizes::BlockSizes{N}) where {N}
exp = Expr(:tuple, [:(block_sizes[$i][end] - 1) for i in 1:N]...)
return quote
@inbounds return $exp
end
end

function Base.show(io::IO, block_sizes::BlockSizes{N}) where {N}
if N == 0
print(io, "[]")
Expand Down
4 changes: 4 additions & 0 deletions src/deprecate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@deprecate BlockArray(blocks::Array{R, N}, block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}} BlockArrays._BlockArray(blocks, block_sizes)
@deprecate BlockArray(blocks::Array{R, N}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}} BlockArrays._BlockArray(blocks, block_sizes...)
@deprecate BlockArray(::Type{R}, block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}} BlockArrays._BlockArray(R, block_sizes)
@deprecate BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}} BlockArrays._BlockArray(R, block_sizes...)
Loading