diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index db26dddb..49427cf4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v7 - uses: julia-actions/setup-julia@v3 with: - version: '1.10' + version: '1' - uses: julia-actions/cache@v3 - name: Install dependencies run: julia --project=docs/ -e 'using Pkg; Pkg.update(); Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml index 0bb0812e..9f17d7e6 100644 --- a/.github/workflows/downstream.yml +++ b/.github/workflows/downstream.yml @@ -40,6 +40,7 @@ jobs: - {repo: LazyArrays.jl, group: JuliaArrays} - {repo: BlockBandedMatrices.jl, group: JuliaLinearAlgebra} - {repo: LazyBandedMatrices.jl, group: JuliaLinearAlgebra} + - {repo: InfiniteArrays.jl, group: JuliaArrays} - {repo: InfiniteLinearAlgebra.jl, group: JuliaLinearAlgebra} steps: diff --git a/Project.toml b/Project.toml index dddf335b..e84383e5 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "BlockArrays" uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -version = "1.9.5" +version = "1.10" [deps] diff --git a/ext/BlockArraysAdaptExt.jl b/ext/BlockArraysAdaptExt.jl index 259b23d4..d8cad922 100644 --- a/ext/BlockArraysAdaptExt.jl +++ b/ext/BlockArraysAdaptExt.jl @@ -2,7 +2,7 @@ module BlockArraysAdaptExt using Adapt using BlockArrays -using BlockArrays: _BlockArray, _BlockedUnitRange +using BlockArrays: _BlockArray, _BlockedUnitRange, BlockedOneTo import Adapt: adapt_structure adapt_structure(to, r::BlockedUnitRange) = _BlockedUnitRange(adapt(to, r.first), map(adapt(to), r.lasts)) diff --git a/src/BlockArrays.jl b/src/BlockArrays.jl index d824ab04..9f5a6ba2 100644 --- a/src/BlockArrays.jl +++ b/src/BlockArrays.jl @@ -8,10 +8,13 @@ export blockaxes, blocksize, blocklength, blockcheckbounds, BlockBoundsError, Bl export blocksizes, blocklengths, blocklasts, blockfirsts, blockisequal, blockequals, blockisapprox export eachblockaxes export BlockRange, blockedrange, BlockedUnitRange, BlockedOneTo +export BlockedUnitRangeFirsts, BlockedUnitRangeLengths export BlockArray, BlockMatrix, BlockVector, BlockVecOrMat, mortar export BlockedArray, BlockedMatrix, BlockedVector, BlockedVecOrMat +export FirstStepRangeLen + export undef_blocks, undef, findblock, findblockindex export khatri_rao, blockkron, BlockKron @@ -28,9 +31,10 @@ import Base: @propagate_inbounds, Array, AbstractArray, to_indices, to_index, RangeIndex, Int, Integer, Number, Tuple, +, -, *, /, \, min, max, isless, in, copy, copyto!, axes, @deprecate, BroadcastStyle, checkbounds, checkindex, ensure_indexable, - oneunit, ones, zeros, intersect, Slice, resize! + oneunit, ones, zeros, intersect, Slice, resize!, accumulate, cumsum, + promote_rule -using Base: ReshapedArray, LogicalIndex, dataids, oneto +using Base: ReshapedArray, LogicalIndex, dataids, oneto, OneTo import Base: (:), IteratorSize, iterate, axes1, strides, isempty import Base.Broadcast: broadcasted, DefaultArrayStyle, AbstractArrayStyle, Broadcasted, broadcastable @@ -39,7 +43,7 @@ import ArrayLayouts: MatLdivVec, MatLmulVec, MatMulMatAdd, MatMulVecAdd, MemoryL conjlayout, rowsupport, sub_materialize, sub_materialize_axes, sublayout, transposelayout, triangulardata, triangularlayout, zero!, materialize! -import FillArrays: axes_print_matrix_row +import FillArrays: axes_print_matrix_row, AbstractFillVector, AbstractZerosVector, AbstractOnesVector, getindex_value import LinearAlgebra: AbstractTriangular, AdjOrTrans, HermOrSym, RealHermSymComplexHerm, StructuredMatrixStyle, lmul!, rmul! @@ -57,6 +61,9 @@ end _maybetail(::Tuple{}) = () _maybetail(t::Tuple) = tail(t) +include("firststeprangelen.jl") +using .FirstStepRange + include("blockindices.jl") include("blockaxis.jl") include("abstractblockarray.jl") diff --git a/src/blockaxis.jl b/src/blockaxis.jl index 94c4d601..e701ea21 100644 --- a/src/blockaxis.jl +++ b/src/blockaxis.jl @@ -17,8 +17,8 @@ # handles plain ranges where block(K) is always Block(1). @propagate_inbounds getindex(b::AbstractUnitRange{<:Integer}, K::BlockIndices{1}) = b[block(K)][K.indices...] -function findblockindex(b::AbstractVector, k::Integer) - @boundscheck k in b || throw(BoundsError()) +@propagate_inbounds function findblockindex(b::AbstractVector, k::Integer) + @boundscheck k in b || throw(BoundsError(b, k)) bl = blocklasts(b) blockidx = _searchsortedfirst(bl, k) @assert blockindex != lastindex(bl) + 1 # guaranteed by the @boundscheck above @@ -93,19 +93,8 @@ first(b::BlockedUnitRange) = b.first BlockedUnitRange(::BlockedUnitRange) = throw(ArgumentError("Forbidden due to ambiguity")) # Use `accumulate` instead of `cumsum` because it preserves the element type of the block lengths _blocklengths2blocklasts(blocks) = accumulate(+, blocks) # extra level to allow changing default accumulate behaviour - -@inline blockfirsts(a::AbstractBlockedUnitRange) = [first(a); @views(blocklasts(a)[1:end-1]) .+ oneunit(eltype(a))] - -# optimize common cases -@inline function blockfirsts(a::AbstractBlockedUnitRange{<:Any,<:Union{Vector, RangeCumsum{<:Any, <:UnitRange}}}) - v = Vector{eltype(a)}(undef, length(blocklasts(a))) - v[1] = first(a) - v[2:end] .= @views(blocklasts(a)[oneto(end-1)]) .+ oneunit(eltype(a)) - return v -end -@inline function blockfirsts(a::AbstractBlockedUnitRange{<:Any,<:Tuple}) - return (first(a), (blocklasts(a)[oneto(end-1)] .+ oneunit(eltype(a)))...) -end +_blocklengths2blocklasts(blocks::AbstractFillVector) = FirstStepRangeLen(getindex_value(blocks), length(blocks)) # encode that the first is the same as step +_blocklengths2blocklasts(blocks::Union{AbstractOnesVector,AbstractZerosVector}) = accumulate(+, blocks) # cumsum of Ones/Zeros gets more precise structure function Base.AbstractUnitRange{T}(r::BlockedUnitRange) where {T} return _BlockedUnitRange(convert(T,first(r)), convert.(T,blocklasts(r))) @@ -130,7 +119,7 @@ This parallels `Base.OneTo` in that the first value is guaranteed to be `1`. Construction is typically via `blockedrange` which converts -a vector of block lengths to a `BlockedUnitRange`. +a vector of block lengths to a `AbstractBlockedUnitRange`. # Examples ```jldoctest @@ -179,17 +168,20 @@ axes(b::BlockedOneTo) = (b,) function Base.AbstractUnitRange{T}(r::BlockedOneTo) where {T} return BlockedOneTo(convert.(T,blocklasts(r))) end - # See: https://github.com/JuliaLang/julia/blob/b06d26075bf7b3f4e7f1b64b120f5665d8ed76f9/base/range.jl#L1006-L1010 function getindex(r::Base.OneTo{T}, s::BlockedOneTo) where T @inline @boundscheck checkbounds(r, s) return BlockedOneTo(convert(AbstractVector{T}, blocklasts(s))) end + + function getindex(r::BlockedOneTo{T}, s::BlockedOneTo) where T return Base.oneto(r)[s] end + + """ blockedrange(blocklengths::Union{Tuple, AbstractVector}) blockedrange(first::Integer, blocklengths::Union{Tuple, AbstractVector}) @@ -218,15 +210,37 @@ julia> blockedrange(2, (1,2)) @inline blockedrange(blocks::Union{Tuple,AbstractVector}) = BlockedOneTo(_blocklengths2blocklasts(blocks)) @inline blockedrange(f::Integer, blocks::Union{Tuple,AbstractVector}) = _BlockedUnitRange(f, f-oneunit(f) .+ _blocklengths2blocklasts(blocks)) -_diff(a::AbstractVector) = diff(a) -_diff(a::Tuple) = diff(collect(a)) -@inline _blocklengths(a, bl, dbl) = isempty(bl) ? [dbl;] : [first(bl)-first(a)+oneunit(eltype(a)); dbl] -@inline function _blocklengths(a::BlockedOneTo, bl::RangeCumsum, ::OrdinalRange) - # the 1:0 is hardcoded here to enable conversions to a Base.OneTo - isempty(bl) ? oftype(bl.range, 1:0) : bl.range +struct BlockedUnitRangeLengths{T<:Integer, LASTS<:AbstractVector{T}} <: AbstractVector{T} + offset::T + lasts::LASTS +end + +struct BlockedUnitRangeFirsts{T<:Integer, LASTS<:AbstractVector{T}} <: AbstractVector{T} + first::T + lasts::LASTS +end + +size(b::Union{BlockedUnitRangeLengths,BlockedUnitRangeFirsts}) = size(b.lasts) + +@propagate_inbounds function getindex(b::BlockedUnitRangeLengths, k::Integer) + if isone(k) + first(b.lasts) - b.offset + else + b.lasts[k] - b.lasts[k-1] + end end -@inline _blocklengths(a, bl) = _blocklengths(a, bl, _diff(bl)) -@inline blocklengths(a::AbstractBlockedUnitRange) = _blocklengths(a, blocklasts(a)) + +@propagate_inbounds function getindex(b::BlockedUnitRangeFirsts{T}, k::Integer) where T + if isone(k) + b.first + else + b.lasts[k-1] + oneunit(T) + end +end + +accumulate(::typeof(+), b::BlockedUnitRangeLengths) = cumsum(b) +cumsum(b::BlockedUnitRangeLengths) = b.lasts .+ b.offset + length(a::AbstractBlockedUnitRange) = isempty(blocklasts(a)) ? zero(eltype(a)) : Integer(last(blocklasts(a))-first(a)+oneunit(eltype(a))) @@ -600,7 +614,7 @@ function findblock(b::AbstractUnitRange{<:Integer}, k::Integer) end """ - blockfirsts(a::AbstractUnitRange{<:Integer}) + blockfirsts(a::AbstractUnitRange) Return the first index of each block of `a`. @@ -618,15 +632,23 @@ julia> b = blockedrange([1,2,3]) 6 julia> blockfirsts(b) -3-element Vector{Int64}: +3-element BlockedUnitRangeFirsts{Int64, Vector{Int64}}: 1 2 4 ``` """ -blockfirsts(a::AbstractUnitRange{<:Integer}) = Ones{eltype(a)}(1) +@inline blockfirsts(a::AbstractUnitRange) = Fill(first(a), 1) +@inline blockfirsts(a::AbstractBlockedUnitRange) = BlockedUnitRangeFirsts(first(a), blocklasts(a)) +@inline blockfirsts(a::BlockedOneTo{<:Any,<:FirstStepRanges}) = blocklasts(a) .- first(blocklasts(a)) .+ oneunit(eltype(a)) + +# special support for tuple indexing +@inline function blockfirsts(a::AbstractBlockedUnitRange{<:Any,<:Tuple}) + return (first(a), (blocklasts(a)[oneto(end-1)] .+ oneunit(eltype(a)))...) +end + """ - blocklasts(a::AbstractUnitRange{<:Integer}) + blocklasts(a::AbstractUnitRange) Return the last index of each block of `a`. @@ -650,9 +672,10 @@ julia> blocklasts(b) 6 ``` """ -blocklasts(a::AbstractUnitRange{<:Integer}) = Fill(eltype(a)(length(a)),1) +@inline blocklasts(a::AbstractUnitRange) = Fill(eltype(a)(length(a)),1) + """ - blocklengths(a::AbstractUnitRange{<:Integer}) + blocklengths(a::AbstractUnitRange) Return the length of each block of `a`. @@ -670,13 +693,21 @@ julia> b = blockedrange([1,2,3]) 6 julia> blocklengths(b) -3-element Vector{Int64}: +3-element BlockedUnitRangeLengths{Int64, Vector{Int64}}: 1 2 3 ``` """ -blocklengths(a::AbstractUnitRange{<:Integer}) = blocklasts(a) .- blockfirsts(a) .+ oneunit(eltype(a)) +@inline blocklengths(a::AbstractUnitRange) = blocklasts(a) +@inline blocklengths(a::AbstractBlockedUnitRange{T}) where T = BlockedUnitRangeLengths(first(a)-oneunit(T), blocklasts(a)) +# special support for tuple indexing +@inline function blocklengths(a::AbstractBlockedUnitRange{<:Any,<:Tuple}) + return (first(blocklasts(a)) - first(a) + oneunit(eltype(a)), (blocklasts(a)[2:end] .- blocklasts(a)[1:end-1])...) +end +blocklengths(a::AbstractBlockedUnitRange{<:Any,Tuple{}}) = () +@inline blocklengths(a::BlockedOneTo{<:Any, <:FirstStepRangeLen}) = Fill(step(blocklasts(a)), length(blocklasts(a))) +@inline blocklengths(a::BlockedOneTo{T,<:OneTo}) where T<:Integer = Ones{T}(length(blocklasts(a))) Base.summary(io::IO, a::AbstractBlockedUnitRange) = _block_summary(io, a) @@ -719,18 +750,6 @@ function blocklengths(a::AbstractBlockedUnitRange{<:Any,<:Base.OneTo{<:Integer}} first(a) == 1 || error("Offset axes not supported") Ones{eltype(a)}(length(blocklasts(a))) end -function blockfirsts(a::AbstractBlockedUnitRange{<:Any,<:AbstractRange}) - st = step(blocklasts(a)) - first(a) == 1 || error("Offset axes not supported") - @assert first(blocklasts(a))-first(a)+oneunit(eltype(a)) == st - range(oneunit(eltype(a)); step=st, length=eltype(a)(length(blocklasts(a)))) -end -function blocklengths(a::AbstractBlockedUnitRange{<:Any,<:AbstractRange}) - st = step(blocklasts(a)) - first(a) == 1 || error("Offset axes not supported") - @assert first(blocklasts(a))-first(a)+oneunit(eltype(a)) == st - Fill(st,length(blocklasts(a))) -end # TODO: Remove diff --git a/src/blockproduct.jl b/src/blockproduct.jl index 43fd9887..593c24b9 100644 --- a/src/blockproduct.jl +++ b/src/blockproduct.jl @@ -151,7 +151,7 @@ julia> A = reshape(1:9, 3, 3) 3 6 9 julia> BlockArrays.blockvec(A) -3-blocked 9-element BlockedVector{Int64, UnitRange{Int64}, Tuple{BlockedOneTo{Int64, StepRangeLen{Int64, Int64, Int64, Int64}}}}: +3-blocked 9-element BlockedVector{Int64, UnitRange{Int64}, Tuple{BlockedOneTo{Int64, FirstStepRangeLen{Int64, Int64, Int64}}}}: 1 2 3 diff --git a/src/blocks.jl b/src/blocks.jl index ee23f227..789a8dac 100644 --- a/src/blocks.jl +++ b/src/blocks.jl @@ -144,7 +144,7 @@ julia> A = BlockArray(ones(3,3),[2,1],[1,1,1]) 1.0 │ 1.0 │ 1.0 julia> blocksizes(A) -2×3 BlockArrays.ProductArray{Tuple{Int64, Int64}, 2, Tuple{Vector{Int64}, Vector{Int64}}}: +2×3 BlockArrays.ProductArray{Tuple{Int64, Int64}, 2, Tuple{BlockedUnitRangeLengths{Int64, Vector{Int64}}, BlockedUnitRangeLengths{Int64, Vector{Int64}}}}: (2, 1) (2, 1) (2, 1) (1, 1) (1, 1) (1, 1) @@ -152,7 +152,7 @@ julia> blocksizes(A)[1,2] (2, 1) julia> blocksizes(A,2) -3-element Vector{Int64}: +3-element BlockedUnitRangeLengths{Int64, Vector{Int64}}: 1 1 1 @@ -186,7 +186,7 @@ julia> blocklengths(A)[1,2] ``` """ blocklengths(A::AbstractArray) = BlockLengths(A) -blocklengths(A::AbstractVector) = map(length, blocks(A)) +blocklengths(A::AbstractVector) = blocklengths(axes(A,1)) struct BlockLengths{T,N,A<:AbstractArray{<:Any,N}} <: AbstractArray{T,N} array::A diff --git a/src/firststeprangelen.jl b/src/firststeprangelen.jl new file mode 100644 index 00000000..5d88bbd7 --- /dev/null +++ b/src/firststeprangelen.jl @@ -0,0 +1,129 @@ +### +# based on julia/base/range.jl +### +module FirstStepRange +using Base + +import Base: el_same, StepRangeLen, step, step_hp, getindex, unsafe_getindex, length, first, last, iterate, OneTo, promote_rule, isempty, show, ==, -, + +import Base: _reverse +import Base: broadcasted +using Base.Broadcast: DefaultArrayStyle + +export FirstStepRangeLen, FirstStepRanges + +""" + FirstStepRangeLen(step::S, len) where S + FirstStepRangeLen{T}(step::S, len) where {S, T} + +A range `r` where `r[i]` produces values of type `T` (in the first +form, `T` is deduced automatically), a `step`, and the `len`gth. The `step` is also the starting +value `r[1]`. This is used to encode block lasts corresponding to a fixed block size. +""" +struct FirstStepRangeLen{T,S,L<:Integer} <: AbstractRange{T} + step::S # step value + len::L # length of the range + + function FirstStepRangeLen{T,S,L}(step::S, len::Integer) where {T,S,L} + if T <: Integer && !isinteger(step + step) + throw(ArgumentError("FirstStepRangeLen{<:Integer} cannot have non-integer step")) + end + len = convert(L, len) + len >= zero(len) || throw(ArgumentError("length cannot be negative, got $len")) + L1 = oneunit(typeof(len)) + return new(step, len) + end +end + +FirstStepRangeLen{T,S}(step::S, len::Integer) where {T,S} = + FirstStepRangeLen{T,S,promote_type(Int,typeof(len))}(step, len) +FirstStepRangeLen(step::S, len::Integer) where {S} = + FirstStepRangeLen{typeof(zero(step)+zero(step)),S,promote_type(Int,typeof(len))}(step, len) +FirstStepRangeLen{T}(step::S, len::Integer) where {T,S} = + FirstStepRangeLen{T,S,promote_type(Int,typeof(len))}(step, len) + +isempty(r::FirstStepRangeLen) = length(r) == 0 + +step(r::FirstStepRangeLen) = r.step +step_hp(r::FirstStepRangeLen) = r.step +length(r::FirstStepRangeLen) = r.len +first(r::FirstStepRangeLen) = unsafe_getindex(r, 1) +last(r::FirstStepRangeLen) = unsafe_getindex(r, length(r)) + +StepRangeLen(r::FirstStepRangeLen{T}) where T = StepRangeLen{T}(first(r), step(r), length(r)) + + +iterate(r::FirstStepRangeLen, i...) = iterate(StepRangeLen(r), i...) +unsafe_getindex(r::FirstStepRangeLen{T}, i::Integer) where T = T(step(r)i) +getindex(r::FirstStepRangeLen{T}, s::OrdinalRange{S}) where {T, S<:Integer} = StepRangeLen(r)[s] + +function show(io::IO, r::FirstStepRangeLen) + if !iszero(step(r)) + print(io, repr(first(r)), ':', repr(step(r)), ':', repr(last(r))) + else + # ugly temporary printing, to avoid 0:0:0 etc. + print(io, "FirstStepRangeLen(", repr(first(r)), ", ", repr(step(r)), ", ", repr(length(r)), ")") + end +end + +==(r::FirstStepRangeLen, s::FirstStepRangeLen) = + (isempty(r) & isempty(s)) | ((length(r) == length(s)) & (last(r) == last(s))) + +==(r::FirstStepRangeLen{T}, s::Union{StepRange{T},StepRangeLen{T,T}}) where {T} = StepRangeLen(r) == s +==(r::Union{StepRange{T},StepRangeLen{T,T}}, s::FirstStepRangeLen{T}) where {T} = r == StepRangeLen(s) + + +-(r::FirstStepRangeLen{T,S,L}) where {T,S,L} = FirstStepRangeLen{T,S,L}(-r.step, r.len) + +function promote_rule(::Type{FirstStepRangeLen{T1,S1,L1}},::Type{FirstStepRangeLen{T2,S2,L2}}) where {T1,T2,S1,S2,L1,L2} + S, L = promote_type(S1, S2), promote_type(L1, L2) + el_same(promote_type(T1, T2), FirstStepRangeLen{T1,S,L}, FirstStepRangeLen{T2,S,L}) +end +FirstStepRangeLen{T,S,L}(r::FirstStepRangeLen{T,S,L}) where {T,S,L} = r +FirstStepRangeLen{T,S,L}(r::FirstStepRangeLen) where {T,S,L} = + FirstStepRangeLen{T,S,L}(convert(S, r.step), convert(L, r.len)) +FirstStepRangeLen{T}(r::FirstStepRangeLen) where {T} = + FirstStepRangeLen(convert(T, r.step), r.len) + +promote_rule(a::Type{FirstStepRangeLen{T,S,L}}, ::Type{OR}) where {T,S,L,OR<:AbstractRange} = + promote_rule(a, FirstStepRangeLen{eltype(OR), eltype(OR), Int}) + +promote_rule(::Type{LinRange{A,L}}, b::Type{FirstStepRangeLen{T2,S2,L2}}) where {A,L,T2,S2,L2} = + promote_rule(FirstStepRangeLen{A,A,L}, b) + + +_reverse(r::FirstStepRangeLen, ::Colon) = typeof(r)(negate(r.step), length(r), offset) + +function +(r1::FirstStepRangeLen{T,S}, r2::FirstStepRangeLen{T,S}) where {T,S} + len = length(r1) + (len == length(r2) || + throw(DimensionMismatch("argument dimensions must match: length of r1 is $len, length of r2 is $(length(r2))"))) + FirstStepRangeLen(step(r1)+step(r2), len) +end + +-(r1::FirstStepRangeLen, r2::FirstStepRangeLen) = +(r1, -r2) + + +const FirstStepRanges = Union{FirstStepRangeLen, OneTo} + + +###### +# from base/broadcast.jl +###### + +broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::FirstStepRangeLen) = FirstStepRangeLen(negate(r.step), length(r)) +for op in (:+, :-) + @eval begin + broadcasted(::DefaultArrayStyle{1}, ::typeof($op), r::FirstStepRangeLen{T}, x::Number) where T = broadcasted(DefaultArrayStyle{1}(), $op, StepRangeLen(r), x) + broadcasted(::DefaultArrayStyle{1}, ::typeof($op), x::Number, r::FirstStepRangeLen{T}) where T = broadcasted(DefaultArrayStyle{1}(), $op, x, StepRangeLen(r)) + end +end +broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::FirstStepRangeLen{T}) where {T} = + FirstStepRangeLen{typeof(x*T(r.step))}(x*r.step, length(r)) +broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::FirstStepRangeLen{T}, x::Number) where {T} = + FirstStepRangeLen{typeof(T(r.step)*x)}(r.step*x, length(r)) +broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::FirstStepRangeLen{T}, x::Number) where {T} = + FirstStepRangeLen{typeof(T(r.step)/x)}(r.step/x, length(r)) +broadcasted(::DefaultArrayStyle{1}, ::typeof(\), x::Number, r::FirstStepRangeLen) = FirstStepRangeLen(x\r.step, length(r)) +broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::FirstStepRangeLen) = FirstStepRangeLen(big(r.step), length(r)) + +end # module \ No newline at end of file diff --git a/test/test_blockarrayinterface.jl b/test/test_blockarrayinterface.jl index 57581398..60aeaffa 100644 --- a/test/test_blockarrayinterface.jl +++ b/test/test_blockarrayinterface.jl @@ -146,14 +146,14 @@ end @test axes(D) isa NTuple{2,BlockedOneTo} @test blockisequal(axes(D, 1), axes(parent(D), 1)) @test D == Diagonal(Vector(parent(D))) - @test MemoryLayout(D) isa BlockArrays.DiagonalLayout{<:BlockArrays.BlockLayout} + @test MemoryLayout(D) isa ArrayLayouts.DiagonalLayout{<:BlockArrays.BlockLayout} end @testset "non-standard block axes" begin A = BlockArray([1 2; 3 4], Fill(1, 2), Fill(1, 2)) - @test A isa BlockMatrix{Int,Matrix{Matrix{Int}},<:NTuple{2,BlockedOneTo{Int,<:AbstractRange}}} + @test A isa BlockMatrix{Int,Matrix{Matrix{Int}},<:NTuple{2,BlockedOneTo{Int,<:BlockArrays.FirstStepRangeLen}}} A = BlockArray([1 2; 3 4], Fill(1, 2), [1, 1]) - @test A isa BlockMatrix{Int,Matrix{Matrix{Int}},<:Tuple{BlockedOneTo{Int,<:AbstractRange},BlockedOneTo{Int,Vector{Int}}}} + @test A isa BlockMatrix{Int,Matrix{Matrix{Int}},<:Tuple{BlockedOneTo{Int,<:BlockArrays.FirstStepRangeLen},BlockedOneTo{Int,Vector{Int}}}} end @testset "block Fill" begin diff --git a/test/test_blockcholesky.jl b/test/test_blockcholesky.jl index 0eb5dca3..c3d96099 100644 --- a/test/test_blockcholesky.jl +++ b/test/test_blockcholesky.jl @@ -26,11 +26,7 @@ Random.seed!(0) D_T = Matrix(D) #Test on nonsymmetric matrix - if VERSION < v"1.8-" - @test_throws MethodError cholesky(nsym) - else - @test_throws DimensionMismatch cholesky(nsym) - end + @test_throws DimensionMismatch cholesky(nsym) #Tests on A @test cholesky(A).U ≈ cholesky(A_T).U diff --git a/test/test_blockindices.jl b/test/test_blockindices.jl index 9cfcc32e..eb745555 100644 --- a/test/test_blockindices.jl +++ b/test/test_blockindices.jl @@ -4,6 +4,7 @@ using BlockArrays, FillArrays, Test, StaticArrays, ArrayLayouts using OffsetArrays import BlockArrays: BlockIndex, BlockIndexRange, BlockSlice, NoncontiguousBlockSlice import BlockArrays: split_index, merge_indices +using BlockArrays.FirstStepRange @testset "Blocks" begin @test Int(Block(2)) === Integer(Block(2)) === Number(Block(2)) === 2 @@ -276,9 +277,9 @@ end @test @inferred(blocklengths(o)) == Ones{Int}(10) f = blockedrange(1, Fill(2,5)) - @test @inferred(blockfirsts(f)) ≡ 1:2:9 + @test @inferred(blockfirsts(f)) == 1:2:9 @test @inferred(blocklasts(f)) ≡ StepRangeLen(2,2,5) - @test @inferred(blocklengths(f)) ≡ Fill(2,5) + @test @inferred(blocklengths(f)) == Fill(2,5) f = blockedrange(1, Zeros{Int}(2)) @test @inferred(blockfirsts(f)) == [1,1] @@ -490,7 +491,7 @@ end # we support Tuples in addition to SVectors for InfiniteArrays.jl, which has # infinite block sizes s = blockedrange(1, (5,big(100_000_000)^2)) - @test blocklengths(s) == [5,big(100_000_000)^2] + @test blocklengths(s) == (5,big(100_000_000)^2) @test blockaxes(s) == (Block.(1:2),) @test findblock(s,3) == Block(1) @test findblock(s,big(100_000_000)) == Block(2) @@ -563,9 +564,9 @@ end @test @inferred(blocklengths(o)) == Ones{Int}(10) f = blockedrange(Fill(2,5)) - @test @inferred(blockfirsts(f)) ≡ 1:2:9 - @test @inferred(blocklasts(f)) ≡ StepRangeLen(2,2,5) - @test @inferred(blocklengths(f)) ≡ Fill(2,5) + @test @inferred(blockfirsts(f)) == 1:2:9 + @test @inferred(blocklasts(f)) ≡ FirstStepRangeLen(2,5) + @test @inferred(blocklengths(f)) == Fill(2,5) f = blockedrange(Zeros{Int}(2)) @test @inferred(blockfirsts(f)) == [1,1] @@ -594,6 +595,7 @@ end b = blockedrange(Fill(2,3)) c = blockedrange([2,2,2]) @test convert(BlockedOneTo, b) === b + @test convert(BlockedOneTo, b) === BlockedOneTo(b.lasts) @test convert(typeof(b), b) === b @test convert(BlockedOneTo, c) === c @test convert(typeof(c), c) === c @@ -764,7 +766,7 @@ end @test eltype(s) === BigInt @test first(s) isa BigInt @test last(s) isa BigInt - @test blocklengths(s) == [5,big(100_000_000)^2] + @test blocklengths(s) == (5,big(100_000_000)^2) @test eltype(blocklengths(s)) === BigInt @test blockaxes(s) == (Block.(1:2),) @test findblock(s,3) == Block(1) @@ -777,7 +779,7 @@ end @test length(r) === 6 @test blockfirsts(r) === (1, 3, 5) @test blocklasts(r) === (2, 4, 6) - @test blocklengths(r) == [2, 2, 2] + @test blocklengths(r) == (2, 2, 2) end @testset "Empty Tuple" begin @@ -788,7 +790,7 @@ end @test length(r) === 0 @test blockfirsts(r) === (1,) @test blocklasts(r) === () - @test blocklengths(r) == [] + @test blocklengths(r) == () end @testset "General element types" begin @@ -815,15 +817,15 @@ end @test eltype(blockedrange(one(elt), Base.OneTo(elt(3)))) === elt @test eltype(blockedrange(one(elt), elt(1):elt(3))) === elt - if VERSION >= v"1.7" - # `cumsum(::Fill)` doesn't preserve element types properly. - # That issue was fixed by this fix to `StepRangeLen`: - # https://github.com/JuliaLang/julia/pull/41619 - # which is only available in Julia v1.7 and higher. - r = blockedrange(one(elt), Fill(elt(2), 3)) - @test r isa BlockedUnitRange{elt,<:StepRangeLen{elt}} - @test eltype(r) === elt - end + + # `cumsum(::Fill)` doesn't preserve element types properly. + # That issue was fixed by this fix to `StepRangeLen`: + # https://github.com/JuliaLang/julia/pull/41619 + # which is only available in Julia v1.7 and higher. + r = blockedrange(one(elt), Fill(elt(2), 3)) + @test r isa BlockedUnitRange{elt,<:StepRangeLen{elt}} + @test eltype(r) === elt + r = blockedrange(one(elt), Ones(elt, 3)) @test r isa BlockedUnitRange{elt} @@ -871,7 +873,7 @@ end @test last(r) === UInt16(5) @test blockfirsts(r) === (UInt16(1), UInt16(3)) @test blocklasts(r) === (UInt16(2), UInt16(5)) - @test blocklengths(r) == [UInt16(2), UInt16(3)] + @test blocklengths(r) === (UInt16(2), UInt16(3)) @test eltype(blocklengths(r)) === UInt16 end diff --git a/test/test_blockrange.jl b/test/test_blockrange.jl index ffb2ba2b..15ec0c80 100644 --- a/test/test_blockrange.jl +++ b/test/test_blockrange.jl @@ -126,6 +126,11 @@ end @test bi == collect(bi) @test size(bi) == (2,2) end + + @testset "BlockedOneTo(::AbstractRange)" begin + @test blocklengths(BlockedOneTo(2:5)) == [2,1,1,1] + @test blockfirsts(BlockedOneTo(2:5)) == [1,3,4,5] + end end end # module