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 6 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.

29 changes: 22 additions & 7 deletions docs/src/man/blockarrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@ DocTestSetup = quote
end
```


## Creating initialized `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:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps we should mention that the arrays themselves are initialized, the values in them are not? What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

Is this behaviour going to change in 0.7 so that Matrix{Float64}(n,m) automatically sets the values?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think it will, but not sure.

Copy link
Member Author

@dlfivefifty dlfivefifty Nov 28, 2017

Choose a reason for hiding this comment

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

I'm a bit confused about the difference between Matrix{Float64}(uninitialized, n, m) and Matrix{Float64}(n, m).

I'm worried that there's a confusion between uninitialized blocks and uninitialized entries with using uninitialized to mean uninitialized blocks. Especially since I'm hoping to making PseudoBlockArray and BlockArray have equivalent behaviour for the same syntax.

It might be better to add a UninitializedBlocks and then we have the following three cases:

  1. BlockArray{Float64}(uninitialized_blocks, ns), which does not initialize the blocks, i.e., A.blocks[1] is #undef. This is the current behaviour of BlockArray(Vector{Float64}, ns)
  2. BlockArray{Float64}(uninitialized, ns), which initializes the blocks, but not the entries of the blocks, i.e., A.blocks[1] is allocated as a Vector{Float64}(uninitialized, ns[1])
  3. BlockArray{Float64}(ns), which does initialize the blocks, and the entries, i.e., A.blocks[1] is allocated as a Vector{Float64}(ns[1])
  4. PseudoBlockArray{Float64}(uninitialized, ns), A. blocks is allocated as a Vector{Float64}(uninitialized, sum(ns))
  5. PseudoBlockArray{Float64}(ns), which does initialize the blocks, and the entries, i.e., A.blocks is allocated as a Vector{Float64}(sum(ns))

```julia
julia> BlockArray{Float32}([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 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:
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(uninitialized, Matrix{Float32}, [1,2], [3,2])
2×2-blocked 3×5 BlockArrays.BlockArray{Float32,2,Array{Float32,2}}:
#undef #undef #undef │ #undef #undef
------------------------┼----------------
Expand All @@ -23,13 +38,13 @@ julia> BlockArray(Matrix{Float32}, [1,2], [3,2])
We can also use a `SparseVector` or any other user defined array type:

```jl
julia> BlockArray(SparseVector{Float64, Int}, [1,2])
julia> BlockArray(uninitialized, 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])
julia> BlockArray(uninitialized, 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 = BlockArrays._BlockArray(Matrix{Float64}, [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 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> PseudoBlockArray{Float32}([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
2 changes: 1 addition & 1 deletion src/BlockArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ include("blockrange.jl")
include("views.jl")
include("convert.jl")
include("show.jl")

include("deprecate.jl")

end # module
99 changes: 71 additions & 28 deletions src/blockarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
# BlockArray #
##############

function _BlockArray end

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

Expand All @@ -16,15 +18,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 +37,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_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, 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 +65,54 @@ 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(::Uninitialized, ::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
uninitialized_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)


@generated function initialized_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_BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
initialized_BlockArray(R, BlockSizes(block_sizes...))
end

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

function BlockArray(arr::AbstractArray{T, N}, block_sizes::Vararg{Vector{Int}, N}) where {T,N}
@inline function BlockArray{T, N}(block_sizes::BlockSizes{N}) where {T, N}
initialized_BlockArray(Array{T, N}, block_sizes)
end

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

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

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

@inline function BlockArray{T, N, R}(block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N, R <: AbstractArray{T, N}}
initialized_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 +123,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 +134,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 +160,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...)
33 changes: 28 additions & 5 deletions src/pseudo_blockarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ PseudoBlockArray(blocks::R, block_sizes::Vararg{AbstractVector{Int}, N}) where {
PseudoBlockArray(blocks, Vector{Int}.(block_sizes)...)



@inline function PseudoBlockArray{T}(block_sizes::BlockSizes{N}) where {T, N}
Copy link
Member

Choose a reason for hiding this comment

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

Presumably all these new PseudoBlockArray constructors should use uninitialized?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes I think you are right, even if the package supports 0.6.

My only hesitation is that sometimes changes in Julia master are backtracked on, but in this case that’s unlikely to happen.

PseudoBlockArray(similar(Array{T, N}, size(block_sizes)), block_sizes)
end

@inline function PseudoBlockArray{T, N}(block_sizes::BlockSizes{N}) where {T, N}
PseudoBlockArray{T}(block_sizes)
end

@inline function PseudoBlockArray{T, N, R}(block_sizes::BlockSizes{N}) where {T, N, R <: AbstractArray{T, N}}
PseudoBlockArray(similar(R, size(block_sizes)), block_sizes)
end

@inline function PseudoBlockArray{T}(block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N}
PseudoBlockArray{T}(BlockSizes(block_sizes...))
end

@inline function PseudoBlockArray{T, N}(block_sizes::Vararg{AbstractVector{Int}, N}) where {T, N}
PseudoBlockArray{T, N}(BlockSizes(block_sizes...))
end

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


###########################
# AbstractArray Interface #
###########################
Expand All @@ -68,11 +94,8 @@ function Base.similar(block_array::PseudoBlockArray{T,N}, ::Type{T2}) where {T,N
PseudoBlockArray(similar(block_array.blocks, T2), copy(block_array.block_sizes))
end

@generated function Base.size(arr::PseudoBlockArray{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::PseudoBlockArray{T,N}) where {T,N}
size(arr.block_sizes)
end

@inline function Base.getindex(block_arr::PseudoBlockArray{T, N}, i::Vararg{Int, N}) where {T,N}
Expand Down
Loading