Skip to content

Commit

Permalink
Merge branch 'release-1.0' into jishnub/blockedoneto
Browse files Browse the repository at this point in the history
  • Loading branch information
jishnub authored Apr 1, 2024
2 parents 3693956 + 9d8a552 commit b63f5a0
Show file tree
Hide file tree
Showing 12 changed files with 322 additions and 145 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ on:
- 'LICENSE.md'
- 'README.md'
- '.github/workflows/TagBot.yml'

concurrency:
group: build-${{ github.event.pull_request.number || github.ref }}-${{ github.workflow }}
cancel-in-progress: true

jobs:
pre_job:
# continue-on-error: true # Uncomment once integration is finished
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ on:
- 'README.md'
- '.github/workflows/TagBot.yml'

concurrency:
group: build-${{ github.event.pull_request.number || github.ref }}-${{ github.workflow }}
cancel-in-progress: true

jobs:
build:
permissions:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/downstream.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ on:
- 'README.md'
- '.github/workflows/TagBot.yml'

concurrency:
group: build-${{ github.event.pull_request.number || github.ref }}-${{ github.workflow }}
cancel-in-progress: true

jobs:
pre_job:
# continue-on-error: true # Uncomment once integration is finished
Expand All @@ -32,6 +36,7 @@ jobs:
package:
- {repo: BlockBandedMatrices.jl, group: JuliaLinearAlgebra}
- {repo: ApproxFunBase.jl, group: JuliaApproximation}
- {repo: LazyBandedMatrices.jl, group: JuliaLinearAlgebra}
# - {repo: InfiniteLinearAlgebra.jl, group: JuliaLinearAlgebra}

steps:
Expand Down
6 changes: 4 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "BlockArrays"
uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
version = "1.0.0"
version = "1.0.0-dev"

[deps]
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
Expand All @@ -12,6 +12,7 @@ Aqua = "0.8"
ArrayLayouts = "1.0.8"
Documenter = "1"
FillArrays = "1"
JET = "0.4, 0.6, 0.7, 0.8"
LinearAlgebra = "1.6"
OffsetArrays = "1"
Random = "1.6"
Expand All @@ -23,11 +24,12 @@ julia = "1.6"
[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Aqua", "Documenter", "OffsetArrays", "SparseArrays", "StaticArrays", "Test", "Random"]
test = ["Aqua", "Documenter", "JET", "OffsetArrays", "SparseArrays", "StaticArrays", "Test", "Random"]
3 changes: 3 additions & 0 deletions docs/src/lib/public.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ blockcheckbounds

```@docs
BlockArray
BlockArray(::UndefBlocksInitializer, ::Type{R}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N, R<:AbstractArray{T,N}}
BlockArray{T}(::UndefBlocksInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N}
BlockArray{T}(::UndefInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N}
undef_blocks
UndefBlocksInitializer
mortar
Expand Down
160 changes: 114 additions & 46 deletions src/blockarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Singleton type used in block array initialization, indicating the
array-constructor-caller would like an uninitialized block array. See also
undef_blocks (@ref), an alias for UndefBlocksInitializer().
[`undef_blocks`](@ref), an alias for `UndefBlocksInitializer()`.
# Examples
```jldoctest
Expand All @@ -28,8 +28,8 @@ struct UndefBlocksInitializer end
"""
undef_blocks
Alias for UndefBlocksInitializer(), which constructs an instance of the singleton
type UndefBlocksInitializer (@ref), used in block array initialization to indicate the
Alias for `UndefBlocksInitializer()`, which constructs an instance of the singleton
type [`UndefBlocksInitializer`](@ref), used in block array initialization to indicate the
array-constructor-caller would like an uninitialized block array.
# Examples
Expand Down Expand Up @@ -97,21 +97,83 @@ end
_BlockArray(R, block_sizes...)

"""
Constructs a `BlockArray` with uninitialized blocks from a block type `R` with sizes defined by `block_sizes`.
BlockArray(::UndefBlocksInitializer, ::Type{R}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {N,R<:AbstractArray{<:Any,N}}
Construct a `N`-dim `BlockArray` with uninitialized blocks from a block type `R`, with sizes defined by `block_sizes`.
Each block **must** be allocated before being accessed.
# Examples
```jldoctest
julia> BlockArray(undef_blocks, Matrix{Float64}, [1,3], [2,2])
julia> B = BlockArray(undef_blocks, Matrix{Float64}, [1,3], [2,2])
2×2-blocked 4×4 BlockMatrix{Float64}:
#undef #undef │ #undef #undef
────────────────┼────────────────
#undef #undef │ #undef #undef
#undef #undef │ #undef #undef
#undef #undef │ #undef #undef
julia> typeof(blocks(B))
Matrix{Matrix{Float64}} (alias for Array{Array{Float64, 2}, 2})
julia> using SparseArrays
julia> B = BlockArray(undef_blocks, SparseMatrixCSC{Float64,Int}, [1,3], [2,2]);
julia> typeof(blocks(B))
Matrix{SparseMatrixCSC{Float64, Int64}} (alias for Array{SparseMatrixCSC{Float64, Int64}, 2})
```
See also [`undef_blocks`](@ref), [`UndefBlocksInitializer`](@ref)
"""
@inline BlockArray(::UndefBlocksInitializer, ::Type{R}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N, R<:AbstractArray{T,N}} =
undef_blocks_BlockArray(Array{R,N}, block_sizes...)

"""
BlockArray{T}(::UndefBlocksInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T,N}
Construct a `N`-dim `BlockArray` with uninitialized blocks of type `Array{T,N}`, with sizes defined by `block_sizes`.
Each block **must** be allocated before being accessed.
# Examples
```jldoctest
julia> B = BlockArray{Float64}(undef_blocks, [1,2], [1,2])
2×2-blocked 3×3 BlockMatrix{Float64}:
#undef │ #undef #undef
────────┼────────────────
#undef │ #undef #undef
#undef │ #undef #undef
julia> typeof(blocks(B))
Matrix{Matrix{Float64}} (alias for Array{Array{Float64, 2}, 2})
julia> B = BlockArray{Int8}(undef_blocks, [1,2])
2-blocked 3-element BlockVector{Int8}:
#undef
──────
#undef
#undef
julia> typeof(blocks(B))
Vector{Vector{Int8}} (alias for Array{Array{Int8, 1}, 1})
julia> B[Block(1)] .= 2 # errors, as the block is not allocated yet
ERROR: UndefRefError: access to undefined reference
[...]
julia> B[Block(1)] = [1]; # assign an array to the block
julia> B[Block(2)] = [2,3];
julia> B
2-blocked 3-element BlockVector{Int8}:
1
2
3
```
See also [`undef_blocks`](@ref), [`UndefBlocksInitializer`](@ref)
"""
@inline BlockArray{T}(::UndefBlocksInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N} =
BlockArray(undef_blocks, Array{T,N}, block_sizes...)

Expand All @@ -121,16 +183,12 @@ julia> BlockArray(undef_blocks, Matrix{Float64}, [1,3], [2,2])
@inline BlockArray{T,N,R}(::UndefBlocksInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}} =
undef_blocks_BlockArray(R, block_sizes...)

@generated function initialized_blocks_BlockArray(::Type{R}, baxes::NTuple{N,AbstractUnitRange{Int}}) where R<:AbstractArray{V,N} where {T,N,V<:AbstractArray{T,N}}
return quote
block_arr = _BlockArray(R, baxes)
@nloops $N i i->blockaxes(baxes[i],1) begin
block_index = @ntuple $N i
block_arr[block_index...] = similar(V, length.(getindex.(baxes, block_index)))
end

return block_arr
function initialized_blocks_BlockArray(::Type{R}, baxes::NTuple{N,AbstractUnitRange{Int}}) where R<:AbstractArray{V,N} where {T,N,V<:AbstractArray{T,N}}
blocks = map(Iterators.product(map(x -> blockaxes(x,1), baxes)...)) do block_index
indices = map((x,y) -> x[y], baxes, block_index)
similar(V, map(length, indices))
end
return _BlockArray(convert(R, blocks), baxes)
end


Expand All @@ -149,6 +207,28 @@ initialized_blocks_BlockArray(::Type{R}, block_sizes::Vararg{AbstractVector{<:In
@inline BlockArray{T,N,R,BS}(::UndefInitializer, baxes::BS) where {T, N, R<:AbstractArray{<:AbstractArray{T,N},N}, BS<:NTuple{N,AbstractUnitRange{Int}}} =
initialized_blocks_BlockArray(R, baxes)

"""
BlockArray{T}(::UndefInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N}
Construct a `N`-dim `BlockArray` with blocks of type `Array{T,N}`, with sizes defined by `block_sizes`.
The blocks are allocated using `similar`, and the elements in each block are therefore unitialized.
# Examples
```jldoctest
julia> B = BlockArray{Int8}(undef, [1,2]);
julia> B[Block(1)] .= 2;
julia> B[Block(2)] .= 3;
julia> B
2-blocked 3-element BlockVector{Int8}:
2
3
3
```
"""
@inline BlockArray{T}(::UndefInitializer, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T, N} =
initialized_blocks_BlockArray(Array{Array{T,N},N}, block_sizes...)

Expand All @@ -174,17 +254,12 @@ end
BlockArray(arr::AbstractArray{T, N}, block_sizes::Vararg{AbstractVector{<:Integer}, N}) where {T,N} =
BlockArray{T}(arr, block_sizes...)

@generated function BlockArray{T}(arr::AbstractArray{T, N}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T,N}
return quote
block_arr = _BlockArray(Array{typeof(arr),N}, baxes)
@nloops $N i i->blockaxes(baxes[i],1) begin
block_index = @ntuple $N i
indices = getindex.(baxes,block_index)
block_arr[block_index...] = arr[indices...]
end

return block_arr
function BlockArray{T}(arr::AbstractArray{T, N}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T,N}
blocks = map(Iterators.product(map(x -> blockaxes(x,1), baxes)...)) do block_index
indices = map((x,y) -> x[y], baxes, block_index)
arr[indices...]
end
return _BlockArray(blocks, baxes)
end

BlockArray{T}(arr::AbstractArray{<:Any, N}, baxes::NTuple{N,AbstractUnitRange{Int}}) where {T,N} =
Expand Down Expand Up @@ -277,19 +352,17 @@ end

getsizes(block_sizes, block_index) = getindex.(block_sizes, block_index)

@generated function checksizes(fullsizes::Array{NTuple{N,Int}, N}, block_sizes::NTuple{N,Vector{Int}}) where N
quote
@nloops $N i fullsizes begin
block_index = @ntuple $N i
if fullsizes[block_index...] != getsizes(block_sizes, block_index)
error("size(blocks[", strip(repr(block_index), ['(', ')']),
"]) (= ", fullsizes[block_index...],
") is incompatible with expected size: ",
getsizes(block_sizes, block_index))
end
function checksizes(fullsizes::Array{NTuple{N,Int}, N}, block_sizes::NTuple{N,Vector{Int}}) where N
for I in CartesianIndices(fullsizes)
block_index = Tuple(I)
if fullsizes[block_index...] != getsizes(block_sizes, block_index)
error("size(blocks[", strip(repr(block_index), ['(', ')']),
"]) (= ", fullsizes[block_index...],
") is incompatible with expected size: ",
getsizes(block_sizes, block_index))
end
return fullsizes
end
return fullsizes
end

"""
Expand Down Expand Up @@ -452,18 +525,13 @@ end
# Misc #
########

@generated function Base.Array(block_array::BlockArray{T, N, R}) where {T,N,R}
# TODO: This will fail for empty block array
return quote
arr = Array{eltype(T)}(undef, size(block_array))
@nloops $N i i->blockaxes(block_array,i) begin
block_index = @ntuple $N i
indices = getindex.(axes(block_array), block_index)
arr[indices...] = @view block_array[block_index...]
end

return arr
function Base.Array(block_array::BlockArray{T, N, R}) where {T,N,R}
arr = Array{eltype(T)}(undef, size(block_array))
for block_index in Iterators.product(blockaxes(block_array)...)
indices = getindex.(axes(block_array), block_index)
arr[indices...] = @view block_array[block_index...]
end
return arr
end

function Base.fill!(block_array::BlockArray, v)
Expand Down
2 changes: 1 addition & 1 deletion src/blockaxis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ unsafe_indices(b::AbstractBlockedUnitRange) = axes(b)
last(b::AbstractBlockedUnitRange)::Integer = isempty(blocklasts(b)) ? first(b)-1 : last(blocklasts(b))

# view and indexing are identical for a unitrange
Base.view(b::AbstractBlockedUnitRange, K::Block{1}) = b[K]
view(b::AbstractBlockedUnitRange, K::Block{1}) = b[K]

@propagate_inbounds function getindex(b::AbstractBlockedUnitRange, K::Block{1})
k = Integer(K)
Expand Down
Loading

0 comments on commit b63f5a0

Please sign in to comment.