Skip to content

Commit d55d96e

Browse files
Generalize blockisequal to arrays, introduce blockequals and blockisapprox (#477)
Generalize `blockisequal` to arrays, where the definition is that the axes have the same block structure and the array values compare equal with `isequal`. This PR also introduces `blockequals` and `blockisapprox`, which are like `blockisequal` but use `==` and `isapprox` respectively to compare values. Co-authored-by: Sheehan Olver <[email protected]>
1 parent a4a0b93 commit d55d96e

File tree

4 files changed

+153
-4
lines changed

4 files changed

+153
-4
lines changed

docs/src/lib/public.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ Block
3232
BlockIndex
3333
blockaxes
3434
blockisequal
35+
blockequals
36+
blockisapprox
3537
blocksize
3638
blockfirsts
3739
blocklasts

src/BlockArrays.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ using LinearAlgebra, ArrayLayouts, FillArrays
55
export AbstractBlockArray, AbstractBlockMatrix, AbstractBlockVector, AbstractBlockVecOrMat
66
export Block, getblock, getblock!, setblock!, eachblock, blocks
77
export blockaxes, blocksize, blocklength, blockcheckbounds, BlockBoundsError, BlockIndex, BlockIndexRange
8-
export blocksizes, blocklengths, eachblockaxes, blocklasts, blockfirsts, blockisequal
8+
export blocksizes, blocklengths, blocklasts, blockfirsts, blockisequal, blockequals, blockisapprox
9+
export eachblockaxes
910
export BlockRange, blockedrange, BlockedUnitRange, BlockedOneTo
1011

1112
export BlockArray, BlockMatrix, BlockVector, BlockVecOrMat, mortar

src/blockaxis.jl

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,12 @@ end
225225
length(a::AbstractBlockedUnitRange) = isempty(blocklasts(a)) ? zero(eltype(a)) : Integer(last(blocklasts(a))-first(a)+oneunit(eltype(a)))
226226

227227
"""
228+
blockisequal(a::AbstractArray, b::AbstractArray)
228229
blockisequal(a::AbstractUnitRange{<:Integer}, b::AbstractUnitRange{<:Integer})
229230
230-
Check if `a` and `b` have the same block structure.
231+
Check if `a` and `b` have the same values (compared with `isequal`) and block structure.
232+
233+
See also blockequals and blockisapprox.
231234
232235
# Examples
233236
```jldoctest
@@ -251,6 +254,29 @@ true
251254
252255
julia> blockisequal(b1, b2)
253256
false
257+
258+
julia> A = reshape([1:6;], 2, 3)
259+
2×3 Matrix{Int64}:
260+
1 3 5
261+
2 4 6
262+
263+
julia> B1 = BlockedMatrix(A, [1,1], [1,2])
264+
2×2-blocked 2×3 BlockedMatrix{Int64}:
265+
1 │ 3 5
266+
───┼──────
267+
2 │ 4 6
268+
269+
julia> B2 = BlockedMatrix(A, [1,1], [2,1])
270+
2×2-blocked 2×3 BlockedMatrix{Int64}:
271+
1 3 │ 5
272+
──────┼───
273+
2 4 │ 6
274+
275+
julia> blockisequal(B1, B1)
276+
true
277+
278+
julia> blockisequal(B1, B2)
279+
false
254280
```
255281
"""
256282
blockisequal(a::AbstractUnitRange{<:Integer}, b::AbstractUnitRange{<:Integer}) = first(a) == first(b) && blocklasts(a) == blocklasts(b)
@@ -265,6 +291,92 @@ blockisequal(::Tuple{}, ::Tuple{}) = true
265291
blockisequal(::Tuple, ::Tuple{}) = false
266292
blockisequal(::Tuple{}, ::Tuple) = false
267293

294+
blockisequal(a::AbstractArray, b::AbstractArray) =
295+
blockisequal(axes(a), axes(b)) && isequal(a, b)
296+
297+
"""
298+
blockequals(a::AbstractArray, b::AbstractArray)
299+
300+
Check if `a` and `b` have the same values (compared with `==`) and block structure.
301+
302+
See also blockisequal and blockisapprox.
303+
304+
# Examples
305+
```jldoctest
306+
julia> A = reshape([1:6;], 2, 3)
307+
2×3 Matrix{Int64}:
308+
1 3 5
309+
2 4 6
310+
311+
julia> B1 = BlockedMatrix(A, [1,1], [1,2])
312+
2×2-blocked 2×3 BlockedMatrix{Int64}:
313+
1 │ 3 5
314+
───┼──────
315+
2 │ 4 6
316+
317+
julia> B2 = BlockedMatrix(A, [1,1], [2,1])
318+
2×2-blocked 2×3 BlockedMatrix{Int64}:
319+
1 3 │ 5
320+
──────┼───
321+
2 4 │ 6
322+
323+
julia> blockequals(B1, B1)
324+
true
325+
326+
julia> blockequals(B1, B2)
327+
false
328+
```
329+
"""
330+
blockequals(a::AbstractArray, b::AbstractArray) =
331+
blockisequal(axes(a), axes(b)) && (a == b)
332+
333+
"""
334+
blockisapprox(a::AbstractArray, b::AbstractArray; kwargs...)
335+
336+
Check if `a` and `b` have the same block structure and approximately the same
337+
values, compared with `isapprox`. Accepts the same keyword arguments as `isapprox`.
338+
339+
See also blockisequal and blockequals.
340+
341+
# Examples
342+
```jldoctest
343+
julia> A1 = reshape([1:6;], 2, 3)
344+
2×3 Matrix{Int64}:
345+
1 3 5
346+
2 4 6
347+
348+
julia> A2 = A1 .+ 1e-5
349+
2×3 Matrix{Float64}:
350+
1.00001 3.00001 5.00001
351+
2.00001 4.00001 6.00001
352+
353+
julia> B1 = BlockedMatrix(A1, [1,1], [1,2])
354+
2×2-blocked 2×3 BlockedMatrix{Int64}:
355+
1 │ 3 5
356+
───┼──────
357+
2 │ 4 6
358+
359+
julia> B2 = BlockedMatrix(A2, [1,1], [1,2])
360+
2×2-blocked 2×3 BlockedMatrix{Float64}:
361+
1.00001 │ 3.00001 5.00001
362+
─────────┼──────────────────
363+
2.00001 │ 4.00001 6.00001
364+
365+
julia> B3 = BlockedMatrix(A2, [1,1], [2,1])
366+
2×2-blocked 2×3 BlockedMatrix{Float64}:
367+
1.00001 3.00001 │ 5.00001
368+
──────────────────┼─────────
369+
2.00001 4.00001 │ 6.00001
370+
371+
julia> blockisapprox(B1, B2; atol=1e-4)
372+
true
373+
374+
julia> blockisapprox(B1, B3; atol=1e-4)
375+
false
376+
```
377+
"""
378+
blockisapprox(a::AbstractArray, b::AbstractArray; kwargs...) =
379+
blockisequal(axes(a), axes(b)) && isapprox(a, b; kwargs...)
268380

269381
_shift_blocklengths(::AbstractBlockedUnitRange, bl, f) = bl
270382
_shift_blocklengths(::Any, bl, f) = bl .+ (f - 1)

test/test_blockindices.jl

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,15 +937,49 @@ end
937937
@test B[1,2] == 0
938938
end
939939

940-
@testset "blockisequal" begin
941-
B = BlockArray(rand(4,4), [1,3], [1,3])
940+
@testset "blockisequal, blockequals" begin
941+
A = rand(4,4)
942+
B = BlockArray(A, [1,3], [1,3])
943+
B2 = BlockArray(A, [1,3], [2,2])
944+
B3 = BlockArray(randn(4,4), [1,3], [1,3])
942945
v = BlockArray(rand(4), [1,3])
943946
axB = axes(B)
947+
axB2 = axes(B2)
944948
axv = axes(v)
945949
@test blockisequal(axB, axB)
950+
@test blockisequal(axB[1], axB[1])
951+
@test blockequals(axB[1], axB[1])
952+
@test !blockisequal(axB[2], axB2[2])
953+
@test !blockequals(axB[2], axB2[2])
954+
@test !blockisequal(axB2[2], axB[2])
955+
@test !blockequals(axB2[2], axB[2])
946956
@test blockisequal(axv, axv)
947957
@test !blockisequal(axB, axv)
948958
@test !blockisequal(axv, axB)
959+
960+
@test blockisequal(A, A)
961+
@test blockisequal(B, B)
962+
@test !blockisequal(B, A)
963+
@test !blockisequal(A, B)
964+
@test !blockisequal(B, B2)
965+
@test !blockisequal(B2, B)
966+
@test !blockisequal(B, B3)
967+
@test !blockisequal(B3, B)
968+
end
969+
970+
@testset "blockisapprox" begin
971+
A1 = reshape([1:16;], (4,4))
972+
A2 = A1 .+ 1e-10
973+
B1 = BlockArray(A1, [1,3], [1,3])
974+
B2 = BlockArray(A2, [1,3], [1,3])
975+
B12 = BlockArray(A1, [1,3], [2,2])
976+
@test !blockisapprox(A1, A2; rtol=0)
977+
@test blockisapprox(A1, A2; rtol=1e-9)
978+
@test !blockisapprox(A1, B1; rtol=1e-9)
979+
@test !blockisapprox(B1, B2; rtol=0)
980+
@test blockisapprox(B1, B2; rtol=1e-9)
981+
@test !blockisapprox(B1, B12; rtol=0)
982+
@test !blockisapprox(B1, B12; rtol=1e-9)
949983
end
950984

951985
@testset "BlockIndices" begin

0 commit comments

Comments
 (0)