From 92b7d013957581ccba3ba5e03bd449991a0d54ec Mon Sep 17 00:00:00 2001 From: nhz2 Date: Wed, 28 Jan 2026 13:45:08 -0500 Subject: [PATCH 1/4] Add a cconvert for each unsafe_convert --- src/BlockSkylineMatrix.jl | 3 +++ src/linalg.jl | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/BlockSkylineMatrix.jl b/src/BlockSkylineMatrix.jl index 633ffa6..e46fbb6 100644 --- a/src/BlockSkylineMatrix.jl +++ b/src/BlockSkylineMatrix.jl @@ -456,6 +456,9 @@ _parent_blocks(V::BlockBandedBlock)::Tuple{Int,Int} = MemoryLayout(::Type{<:BlockBandedBlock}) = ColumnMajor() Base.elsize(::Type{<:BlockSkylineMatrix{T,R}}) where {T,R} = Base.elsize(R) +function Base.cconvert(::Type{Ptr{T}}, V::BlockBandedBlock{T}) where T + V +end function Base.unsafe_convert(::Type{Ptr{T}}, V::BlockBandedBlock{T}) where T A = parent(V) K,J = _parent_blocks(V) diff --git a/src/linalg.jl b/src/linalg.jl index b018ae2..5307450 100644 --- a/src/linalg.jl +++ b/src/linalg.jl @@ -105,7 +105,9 @@ sub_materialize(::BlockLayout{<:AbstractBandedLayout}, V, _) = BlockBandedMatrix strides(V::SubBlockSkylineMatrix{<:Any,LL,UU,<:Union{BlockRange1,Block1},Block1}) where {LL,UU} = (1,parent(V).block_sizes.block_strides[Int(parentindices(V)[2].block)]) - +function Base.cconvert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,<:Union{BlockRange1,Block1},Block1}) where {T,LL,UU} + V +end function unsafe_convert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,<:Union{BlockRange1,Block1},Block1}) where {T,LL,UU} A = parent(V) JR = parentindices(V)[2] @@ -117,6 +119,9 @@ end strides(V::SubBlockSkylineMatrix{<:Any,LL,UU,<:BlockRange1,<:BlockIndexRange1}) where {LL,UU} = (1,parent(V).block_sizes.block_strides[Int(Block(parentindices(V)[2]))]) +function Base.cconvert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,<:BlockRange1,<:BlockIndexRange1}) where {T,LL,UU} + V +end function unsafe_convert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,<:BlockRange1,<:BlockIndexRange1}) where {T,LL,UU} A = parent(V) JR = parentindices(V)[2] @@ -127,6 +132,9 @@ function unsafe_convert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,<:Block p + sizeof(T)*(JR.block.indices[1][1]-1)*stride(V,2) end +function Base.cconvert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,BlockIndexRange1,BlockIndexRange1}) where {T,LL,UU} + V +end function unsafe_convert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,BlockIndexRange1,BlockIndexRange1}) where {T,LL,UU} A = parent(V) JR = parentindices(V)[2] From a20d5434dbeba16566d26a30ccf40846b028895e Mon Sep 17 00:00:00 2001 From: nhz2 Date: Wed, 28 Jan 2026 13:46:01 -0500 Subject: [PATCH 2/4] fix spacing --- src/linalg.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/linalg.jl b/src/linalg.jl index 5307450..de246fc 100644 --- a/src/linalg.jl +++ b/src/linalg.jl @@ -105,6 +105,7 @@ sub_materialize(::BlockLayout{<:AbstractBandedLayout}, V, _) = BlockBandedMatrix strides(V::SubBlockSkylineMatrix{<:Any,LL,UU,<:Union{BlockRange1,Block1},Block1}) where {LL,UU} = (1,parent(V).block_sizes.block_strides[Int(parentindices(V)[2].block)]) + function Base.cconvert(::Type{Ptr{T}}, V::SubBlockSkylineMatrix{T,LL,UU,<:Union{BlockRange1,Block1},Block1}) where {T,LL,UU} V end From 4fb160278b59d1cdfee6975e067af0501ffad084 Mon Sep 17 00:00:00 2001 From: nhz2 Date: Wed, 28 Jan 2026 14:06:33 -0500 Subject: [PATCH 3/4] test on nightly --- .github/workflows/ci.yml | 1 + .github/workflows/downstream.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22f0fa5..d3a2a11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,7 @@ jobs: - 'min' - 'lts' - '1' + - 'nightly' os: - ubuntu-latest - macOS-latest diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml index f590f8b..faa2749 100644 --- a/.github/workflows/downstream.yml +++ b/.github/workflows/downstream.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - julia-version: ['1'] + julia-version: ['1', 'nightly'] os: [ubuntu-latest] package: - {repo: ApproxFunBase.jl, group: JuliaApproximation} From c17ec1ca83b1282cc75855608efcbf02fb801c05 Mon Sep 17 00:00:00 2001 From: nhz2 Date: Mon, 25 May 2026 17:13:34 -0400 Subject: [PATCH 4/4] Add more tests --- test/runtests.jl | 43 +++++++++++++++++++++++++++++++++++-- test/test_linalg.jl | 3 +++ test/test_triblockbanded.jl | 5 +++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index a017f93..b30af9a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,8 +2,47 @@ using BlockBandedMatrices using ParallelTestRunner const init_code = quote - using Test - using BlockBandedMatrices + using Test + using BlockBandedMatrices + + function strided_ptr(f, a::AbstractArray{T}) where {T} + a_cconv = Base.cconvert(Ptr{T}, a) + GC.@preserve a_cconv begin + f(Base.unsafe_convert(Ptr{T}, a_cconv)) + end + end + + """ + check_strided_get(a::AbstractArray{T,N}) + + Test that array `a` implements the strided array interface for reading. + Checks stride consistency and that `unsafe_load` matches `getindex`. + """ + function check_strided_get(a::AbstractArray{T,N})::Nothing where {T, N} + if !isbitstype(eltype(a)) + error("a doesn't have isbits elements") + end + # Putting strided_ptr before the loop means that strided_ptr shouldn't error for empty arrays + strided_ptr(a) do a_ptr + for d in 1:N + if stride(a, d) != strides(a)[d] + error("stride(a, d) doesn't equal strides(a)[d] for dimension $(d)") + end + end + for i in CartesianIndices(a) + el_ptr = a_ptr + for d in 1:N + stride_in_bytes = stride(a, d) * Base.elsize(typeof(a)) + first_idx = first(axes(a, d)) + el_ptr += (i[d] - first_idx) * stride_in_bytes + end + if unsafe_load(el_ptr) !== a[i] + error("getindex and unsafe_load mismatch at index $(i)") + end + end + end + nothing + end end # Start with autodiscovered tests diff --git a/test/test_linalg.jl b/test/test_linalg.jl index 92f2380..8a0b9e1 100644 --- a/test/test_linalg.jl +++ b/test/test_linalg.jl @@ -10,6 +10,7 @@ using Test import BandedMatrices: BandError, bandeddata import BlockBandedMatrices: _BandedBlockBandedMatrix +import ..check_strided_get @testset "lmul!/rmul!" begin C = BandedBlockBandedMatrix{Float64}(undef, 1:2,1:2, (1,1), (1,1)) @@ -45,6 +46,7 @@ end @test stride(V,2) == 7 @test unsafe_load(pointer(V)) == 46 @test unsafe_load(pointer(V) + stride(V,2)*sizeof(Float64)) == 53 + check_strided_get(V) x = randn(size(A,2)) @test A*x == (similar(x) .= MulAdd(A,x)) ≈ Matrix(A)*x @@ -87,6 +89,7 @@ end V = view(A, Block(2), Block(2)) @test unsafe_load(Base.unsafe_convert(Ptr{Float64}, bandeddata(V))) == 13.0 + check_strided_get(bandeddata(V)) C = BandedMatrix{Float64}(undef, size(V), 2 .*bandwidths(V)) C .= MulAdd(V,V) diff --git a/test/test_triblockbanded.jl b/test/test_triblockbanded.jl index efda3a7..1790885 100644 --- a/test/test_triblockbanded.jl +++ b/test/test_triblockbanded.jl @@ -12,6 +12,7 @@ import BlockBandedMatrices: MemoryLayout, TriangularLayout, blockrowstop, blockcolstop, ColumnMajor import BlockArrays: blockisequal +import ..check_strided_get @testset "triangular" begin @testset "triangular BandedBlockBandedMatrix mul" begin @@ -156,6 +157,7 @@ import BlockArrays: blockisequal @test unsafe_load(pointer(V)) == A[2,4] @test unsafe_load(pointer(V)+sizeof(Float64)*stride(V,2)) == A[2,5] @test MemoryLayout(typeof(V)) == ColumnMajor() + check_strided_get(V) @test size(V) == (5,3) b = randn(size(V,2)) @@ -174,6 +176,7 @@ import BlockArrays: blockisequal @test unsafe_load(pointer(V)) == A[2,5] @test unsafe_load(pointer(V)+sizeof(Float64)*stride(V,2)) == A[2,6] @test MemoryLayout(typeof(V)) == ColumnMajor() + check_strided_get(V) @test size(V) == (5,2) b = randn(size(V,2)) @@ -194,6 +197,8 @@ import BlockArrays: blockisequal V_22 = view(A, Block(N)[1:N], Block(N)[1:N]) @test unsafe_load(pointer(V_22)) == V_22[1,1] == V[1,1] @test strides(V_22) == strides(V) == (1,9) + check_strided_get(V_22) + check_strided_get(V) b = randn(N) @test copyto!(similar(b) , MulAdd(V,b)) == copyto!(similar(b) , MulAdd(V_22,b)) == Matrix(V)*b ==