Skip to content

Commit a192e2f

Browse files
authored
Fix ambiguity with block range indexing with Symmetric/Hermitian (#209)
1 parent aedaa85 commit a192e2f

File tree

3 files changed

+108
-94
lines changed

3 files changed

+108
-94
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "BlockArrays"
22
uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
3-
version = "0.16.13"
3+
version = "0.16.14"
44

55
[deps]
66
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"

src/abstractblockarray.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ end
183183
@inline Base.getindex(A::AbstractMatrix, kr::AbstractVector, jr::Block) = ArrayLayouts.layout_getindex(A, kr, jr)
184184
@inline Base.getindex(A::AbstractMatrix, kr::BlockRange{1}, jr::BlockRange{1}) = ArrayLayouts.layout_getindex(A, kr, jr)
185185
@inline Base.getindex(A::LayoutMatrix, kr::BlockRange{1}, jr::BlockRange{1}) = ArrayLayouts.layout_getindex(A, kr, jr)
186-
for Typ in (:AbstractTriangular, :Adjoint, :Transpose)
186+
for Typ in (:AbstractTriangular, :Adjoint, :Transpose, :Symmetric, :Hermitian)
187187
@eval @inline Base.getindex(A::$Typ{<:Any,<:LayoutMatrix}, kr::BlockRange{1}, jr::BlockRange{1}) = ArrayLayouts.layout_getindex(A, kr, jr)
188188
end
189189

test/test_blockarrayinterface.jl

Lines changed: 106 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ bview(a, b) = Base.invoke(view, Tuple{AbstractArray,Any}, a, b)
88

99
A = randn(5)
1010
@test blocksize(A) == (1,)
11-
@test blocksize(A,1) == 1
11+
@test blocksize(A, 1) == 1
1212
@test blocksizes(A) == ([5],)
13-
@test blocksizes(A,1) == [5]
13+
@test blocksizes(A, 1) == [5]
1414
@test A[Block(1)] == A
15-
view(A,Block(1))[1] = 2
15+
view(A, Block(1))[1] = 2
1616
@test A[1] == 2
1717
@test_throws BlockBoundsError A[Block(2)]
1818

19-
A = randn(5,5)
20-
@test A[Block(1,1)] == A
19+
A = randn(5, 5)
20+
@test A[Block(1, 1)] == A
2121

2222
@test similar(BlockVector{Float64}, Base.OneTo(5)) isa Vector{Float64}
2323
@test similar(BlockVector{Float64}, 5) isa Vector{Float64}
@@ -35,135 +35,149 @@ end
3535
@test blocksize(U) == blocksize(S) == blocksize(A)
3636
@test blockaxes(U) == blockaxes(S) == blockaxes(A)
3737

38-
@test U[Block(2,2)] == UpperTriangular(A[2:3,2:3])
39-
@test U[Block(2,3)] == A[2:3,4:6]
40-
@test U[Block(3,2)] == zeros(3,2)
41-
@test S[Block(2,2)] == Symmetric(A[2:3,2:3])
42-
@test S[Block(2,3)] == A[2:3,4:6]
43-
@test S[Block(3,2)] == transpose(A[2:3,4:6])
44-
@test H[Block(2,2)] == Hermitian(A[2:3,2:3])
45-
@test H[Block(2,3)] == A[2:3,4:6]
46-
@test H[Block(3,2)] == A[2:3,4:6]'
38+
@test U[Block(2, 2)] == UpperTriangular(A[2:3, 2:3])
39+
@test U[Block(2, 3)] == A[2:3, 4:6]
40+
@test U[Block(3, 2)] == zeros(3, 2)
41+
@test S[Block(2, 2)] == Symmetric(A[2:3, 2:3])
42+
@test S[Block(2, 3)] == A[2:3, 4:6]
43+
@test S[Block(3, 2)] == transpose(A[2:3, 4:6])
44+
@test H[Block(2, 2)] == Hermitian(A[2:3, 2:3])
45+
@test H[Block(2, 3)] == A[2:3, 4:6]
46+
@test H[Block(3, 2)] == A[2:3, 4:6]'
4747

4848
@test stringmime("text/plain", UpperTriangular(A)) == "10×10 UpperTriangular{ComplexF64, PseudoBlockMatrix{ComplexF64, Matrix{ComplexF64}, $(typeof(axes(A)))}} with indices 1:1:10×1:1:10:\n 1.0+0.0im │ 11.0+0.0im 21.0+0.0im │ 31.0+0.0im 41.0+0.0im 51.0+0.0im │ 61.0+0.0im 71.0+0.0im 81.0+0.0im 91.0+0.0im\n ───────────┼──────────────────────────┼──────────────────────────────────────┼─────────────────────────────────────────────────\n ⋅ │ 12.0+0.0im 22.0+0.0im │ 32.0+0.0im 42.0+0.0im 52.0+0.0im │ 62.0+0.0im 72.0+0.0im 82.0+0.0im 92.0+0.0im\n ⋅ │ ⋅ 23.0+0.0im │ 33.0+0.0im 43.0+0.0im 53.0+0.0im │ 63.0+0.0im 73.0+0.0im 83.0+0.0im 93.0+0.0im\n ───────────┼──────────────────────────┼──────────────────────────────────────┼─────────────────────────────────────────────────\n ⋅ │ ⋅ ⋅ │ 34.0+0.0im 44.0+0.0im 54.0+0.0im │ 64.0+0.0im 74.0+0.0im 84.0+0.0im 94.0+0.0im\n ⋅ │ ⋅ ⋅ │ ⋅ 45.0+0.0im 55.0+0.0im │ 65.0+0.0im 75.0+0.0im 85.0+0.0im 95.0+0.0im\n ⋅ │ ⋅ ⋅ │ ⋅ ⋅ 56.0+0.0im │ 66.0+0.0im 76.0+0.0im 86.0+0.0im 96.0+0.0im\n ───────────┼──────────────────────────┼──────────────────────────────────────┼─────────────────────────────────────────────────\n ⋅ │ ⋅ ⋅ │ ⋅ ⋅ ⋅ │ 67.0+0.0im 77.0+0.0im 87.0+0.0im 97.0+0.0im\n ⋅ │ ⋅ ⋅ │ ⋅ ⋅ ⋅ │ ⋅ 78.0+0.0im 88.0+0.0im 98.0+0.0im\n ⋅ │ ⋅ ⋅ │ ⋅ ⋅ ⋅ │ ⋅ ⋅ 89.0+0.0im 99.0+0.0im\n ⋅ │ ⋅ ⋅ │ ⋅ ⋅ ⋅ │ ⋅ ⋅ ⋅ 100.0+0.0im"
4949

5050
V = view(A, Block.(1:2), Block.(1:2))
51-
@test blockisequal(axes(Symmetric(V)), axes(view(A,Block.(1:2), Block.(1:2))))
51+
@test blockisequal(axes(Symmetric(V)), axes(view(A, Block.(1:2), Block.(1:2))))
5252
end
5353

5454
@testset "rect blocks" begin
55-
A = PseudoBlockArray{ComplexF64}(undef, 1:3, fill(3,2))
56-
A .= randn(6,6) .+ im * randn(6,6)
55+
A = PseudoBlockArray{ComplexF64}(undef, 1:3, fill(3, 2))
56+
A .= randn(6, 6) .+ im * randn(6, 6)
5757
U = UpperTriangular(A)
5858
S = Symmetric(A)
5959
H = Hermitian(A)
60-
61-
@test blockisequal(axes(S), (axes(A,2),axes(A,2)))
60+
61+
@test blockisequal(axes(S), (axes(A, 2), axes(A, 2)))
6262
@test blockisequal(axes(U), axes(A))
63-
@test blocksize(S) == (blocksize(S,1),blocksize(S,2)) == (2,2)
64-
@test blocksize(U) == (blocksize(U,1),blocksize(U,2)) == blocksize(A)
65-
@test blockaxes(S) == (blockaxes(S,1),blockaxes(S,2)) == (Block.(1:2), Block.(1:2))
66-
@test blockaxes(U) == (blockaxes(U,1),blockaxes(U,2)) == blockaxes(A)
67-
68-
@test U[Block(2,2)] == A[Block(2,2)]
69-
@test U[Block(3,2)] == triu(A[Block(3,2)])
70-
@test U[Block(3,1)] == zeros(3,3)
71-
@test S[Block(2,2)] == Symmetric(A[4:6,4:6])
72-
@test S[Block(1,2)] == A[1:3,4:6]
73-
@test S[Block(2,1)] == transpose(A[1:3,4:6])
74-
@test H[Block(2,2)] == Hermitian(A[4:6,4:6])
75-
@test H[Block(1,2)] == A[1:3,4:6]
76-
@test H[Block(2,1)] == A[1:3,4:6]'
77-
63+
@test blocksize(S) == (blocksize(S, 1), blocksize(S, 2)) == (2, 2)
64+
@test blocksize(U) == (blocksize(U, 1), blocksize(U, 2)) == blocksize(A)
65+
@test blockaxes(S) == (blockaxes(S, 1), blockaxes(S, 2)) == (Block.(1:2), Block.(1:2))
66+
@test blockaxes(U) == (blockaxes(U, 1), blockaxes(U, 2)) == blockaxes(A)
67+
68+
@test U[Block(2, 2)] == A[Block(2, 2)]
69+
@test U[Block(3, 2)] == triu(A[Block(3, 2)])
70+
@test U[Block(3, 1)] == zeros(3, 3)
71+
@test S[Block(2, 2)] == Symmetric(A[4:6, 4:6])
72+
@test S[Block(1, 2)] == A[1:3, 4:6]
73+
@test S[Block(2, 1)] == transpose(A[1:3, 4:6])
74+
@test H[Block(2, 2)] == Hermitian(A[4:6, 4:6])
75+
@test H[Block(1, 2)] == A[1:3, 4:6]
76+
@test H[Block(2, 1)] == A[1:3, 4:6]'
77+
7878
@test !BlockArrays.hasmatchingblocks(U)
7979
@test BlockArrays.hasmatchingblocks(S)
8080
@test BlockArrays.hasmatchingblocks(H)
8181
end
82+
83+
@testset "getindex ambiguity" begin
84+
A = PseudoBlockArray{ComplexF64}(undef, 1:4, 1:4)
85+
A .= reshape(1:length(A), size(A)) .+ im
86+
S = Symmetric(A)
87+
H = Hermitian(A)
88+
89+
@test S[Block.(1:3), Block.(1:3)] == Symmetric(A[Block.(1:3), Block.(1:3)])
90+
@test H[Block.(1:3), Block.(1:3)] == Hermitian(A[Block.(1:3), Block.(1:3)])
91+
@test S[Block.(1:3), Block(3)] == S[1:6, 4:6]
92+
@test H[Block.(1:3), Block(3)] == H[1:6, 4:6]
93+
@test S[Block(3), Block.(1:3)] == S[4:6, 1:6]
94+
@test H[Block(3), Block.(1:3)] == H[4:6, 1:6]
95+
end
8296
end
8397

8498
@testset "Adjoint/Transpose block arrays" begin
8599
A = PseudoBlockArray{ComplexF64}(undef, (1:4), (2:5))
86-
A .= randn.() .+ randn.().*im
100+
A .= randn.() .+ randn.() .* im
87101

88-
@test blocksize(A') == (4,4)
89-
@test blocksize(Transpose(A)) == (4,4)
102+
@test blocksize(A') == (4, 4)
103+
@test blocksize(Transpose(A)) == (4, 4)
90104

91-
@test A'[Block(2,2)] == A[Block(2,2)]' == A[2:3,3:5]'
92-
@test transpose(A)[Block(2,2)] == transpose(A[2:3,3:5])
93-
@test A'[Block(2,3)] == A[Block(3,2)]'
94-
@test transpose(A)[Block(2,3)] == transpose(A[Block(3,2)])
105+
@test A'[Block(2, 2)] == A[Block(2, 2)]' == A[2:3, 3:5]'
106+
@test transpose(A)[Block(2, 2)] == transpose(A[2:3, 3:5])
107+
@test A'[Block(2, 3)] == A[Block(3, 2)]'
108+
@test transpose(A)[Block(2, 3)] == transpose(A[Block(3, 2)])
95109

96110
@test BlockArray(A') == A'
97111
@test BlockArray(transpose(A)) == transpose(A)
98112

99-
@test A'[Block.(1:2),Block.(1:3)] == A[Block.(1:3),Block.(1:2)]'
100-
@test transpose(A)[Block.(1:2),Block.(1:3)] == transpose(A[Block.(1:3),Block.(1:2)])
113+
@test A'[Block.(1:2), Block.(1:3)] == A[Block.(1:3), Block.(1:2)]'
114+
@test transpose(A)[Block.(1:2), Block.(1:3)] == transpose(A[Block.(1:3), Block.(1:2)])
101115

102-
@test A'[Block.(1:2),Block(1)] == A[Block(1),Block.(1:2)]'
103-
@test A'[Block.(1),Block.(1:3)] == A[Block.(1:3),Block.(1)]'
116+
@test A'[Block.(1:2), Block(1)] == A[Block(1), Block.(1:2)]'
117+
@test A'[Block.(1), Block.(1:3)] == A[Block.(1:3), Block.(1)]'
104118
end
105119

106120
@testset "Diagonal BlockArray" begin
107-
A = mortar(Diagonal(fill([1 2],2)))
108-
@test A isa BlockMatrix{Int,Diagonal{Matrix{Int}, Vector{Matrix{Int}}}}
109-
@test A[Block(1,2)] == [0 0]
110-
@test_throws BlockBoundsError A[Block(1,3)]
121+
A = mortar(Diagonal(fill([1 2], 2)))
122+
@test A isa BlockMatrix{Int,Diagonal{Matrix{Int},Vector{Matrix{Int}}}}
123+
@test A[Block(1, 2)] == [0 0]
124+
@test_throws BlockBoundsError A[Block(1, 3)]
111125
@test A == [1 2 0 0; 0 0 1 2]
112126

113127
N = 3
114-
D = Diagonal(mortar(Fill.(-(0:N)-(0:N).^2, 1:2:2N+1)))
128+
D = Diagonal(mortar(Fill.(-(0:N) - (0:N) .^ 2, 1:2:2N+1)))
115129
@test axes(D) isa NTuple{2,BlockedUnitRange}
116-
@test blockisequal(axes(D,1), axes(parent(D),1))
130+
@test blockisequal(axes(D, 1), axes(parent(D), 1))
117131
@test D == Diagonal(Vector(parent(D)))
118132
@test MemoryLayout(D) isa BlockArrays.DiagonalLayout{<:BlockArrays.BlockLayout}
119133
end
120134

121135
@testset "non-standard block axes" begin
122-
A = BlockArray([1 2; 3 4], Fill(1,2),Fill(1,2))
136+
A = BlockArray([1 2; 3 4], Fill(1, 2), Fill(1, 2))
123137
@test A isa BlockMatrix{Int,Matrix{Matrix{Int}},NTuple{2,BlockedUnitRange{StepRange{Int,Int}}}}
124-
A = BlockArray([1 2; 3 4], Fill(1,2),[1,1])
138+
A = BlockArray([1 2; 3 4], Fill(1, 2), [1, 1])
125139
@test A isa BlockMatrix{Int,Matrix{Matrix{Int}},Tuple{BlockedUnitRange{StepRange{Int,Int}},BlockedUnitRange{Vector{Int}}}}
126140
end
127141

128142
@testset "block Fill" begin
129-
A = Fill(2,(blockedrange([1,2,2]),))
130-
@test A[Block(1)] view(A,Block(1)) Fill(2,1)
131-
@test A[Block.(1:2)] == [2,2,2]
143+
A = Fill(2, (blockedrange([1, 2, 2]),))
144+
@test A[Block(1)] view(A, Block(1)) Fill(2, 1)
145+
@test A[Block.(1:2)] == [2, 2, 2]
132146
@test A[Block.(1:2)] isa Fill
133-
@test view(A,Block.(1:2)) isa Fill
134-
@test 2A Fill(4,axes(A))
135-
136-
F = Fill(2, (blockedrange([1,2,2]),blockedrange(1:3)))
137-
@test F[Block(2,2)] view(F,Block(2,2)) view(F,Block(2),Block(2)) F[Block(2),Block(2)] Fill(2, 2,2)
138-
@test F[Block(2),1:5] view(F,Block(2),1:5) Fill(2, 2,5)
139-
@test F[1:5,Block(2)] view(F,1:5,Block(2)) Fill(2, 5,2)
140-
@test F[:,Block(2)] Fill(2, (axes(F,1),Base.OneTo(2)))
141-
@test F[Block(2),:] Fill(2, (Base.OneTo(2),axes(F,2)))
142-
@test F[Block.(1:2),Block.(1:2)] == Fill(2, (blockedrange([1,2]),blockedrange(1:2)))
143-
144-
O = Ones{Int}((blockedrange([1,2,2]),blockedrange(1:3)))
145-
@test O[Block(2,2)] O[Block(2),Block(2)] Ones{Int}(2,2)
146-
@test O[Block(2),1:5] Ones{Int}(2,5)
147-
@test O[1:5,Block(2)] Ones{Int}(5,2)
148-
@test O[:,Block(2)] Ones{Int}((axes(O,1),Base.OneTo(2)))
149-
@test O[Block(2),:] Ones{Int}((Base.OneTo(2),axes(O,2)))
150-
@test O[Block.(1:2),Block.(1:2)] == Ones{Int}((blockedrange([1,2]),blockedrange(1:2)))
151-
152-
Z = Zeros{Int}((blockedrange([1,2,2]),blockedrange(1:3)))
153-
@test Z[Block(2,2)] Z[Block(2),Block(2)] Zeros{Int}(2,2)
154-
@test Z[Block(2),1:5] Zeros{Int}(2,5)
155-
@test Z[1:5,Block(2)] Zeros{Int}(5,2)
156-
@test Z[:,Block(2)] Zeros{Int}((axes(Z,1),Base.OneTo(2)))
157-
@test Z[Block(2),:] Zeros{Int}((Base.OneTo(2),axes(Z,2)))
158-
@test Z[Block.(1:2),Block.(1:2)] == Zeros{Int}((blockedrange([1,2]),blockedrange(1:2)))
159-
160-
B = Eye((blockedrange([1,2]),))
161-
@test B[Block(2,2)] == Matrix(I,2,2)
162-
163-
C = Eye((blockedrange([1,2,2]),blockedrange([2,2])))
164-
@test C[Block(2,2)] == [0 0; 1.0 0]
165-
166-
U = UpperTriangular(Ones((blockedrange([1,2]),blockedrange([2,1]))))
147+
@test view(A, Block.(1:2)) isa Fill
148+
@test 2A Fill(4, axes(A))
149+
150+
F = Fill(2, (blockedrange([1, 2, 2]), blockedrange(1:3)))
151+
@test F[Block(2, 2)] view(F, Block(2, 2)) view(F, Block(2), Block(2)) F[Block(2), Block(2)] Fill(2, 2, 2)
152+
@test F[Block(2), 1:5] view(F, Block(2), 1:5) Fill(2, 2, 5)
153+
@test F[1:5, Block(2)] view(F, 1:5, Block(2)) Fill(2, 5, 2)
154+
@test F[:, Block(2)] Fill(2, (axes(F, 1), Base.OneTo(2)))
155+
@test F[Block(2), :] Fill(2, (Base.OneTo(2), axes(F, 2)))
156+
@test F[Block.(1:2), Block.(1:2)] == Fill(2, (blockedrange([1, 2]), blockedrange(1:2)))
157+
158+
O = Ones{Int}((blockedrange([1, 2, 2]), blockedrange(1:3)))
159+
@test O[Block(2, 2)] O[Block(2), Block(2)] Ones{Int}(2, 2)
160+
@test O[Block(2), 1:5] Ones{Int}(2, 5)
161+
@test O[1:5, Block(2)] Ones{Int}(5, 2)
162+
@test O[:, Block(2)] Ones{Int}((axes(O, 1), Base.OneTo(2)))
163+
@test O[Block(2), :] Ones{Int}((Base.OneTo(2), axes(O, 2)))
164+
@test O[Block.(1:2), Block.(1:2)] == Ones{Int}((blockedrange([1, 2]), blockedrange(1:2)))
165+
166+
Z = Zeros{Int}((blockedrange([1, 2, 2]), blockedrange(1:3)))
167+
@test Z[Block(2, 2)] Z[Block(2), Block(2)] Zeros{Int}(2, 2)
168+
@test Z[Block(2), 1:5] Zeros{Int}(2, 5)
169+
@test Z[1:5, Block(2)] Zeros{Int}(5, 2)
170+
@test Z[:, Block(2)] Zeros{Int}((axes(Z, 1), Base.OneTo(2)))
171+
@test Z[Block(2), :] Zeros{Int}((Base.OneTo(2), axes(Z, 2)))
172+
@test Z[Block.(1:2), Block.(1:2)] == Zeros{Int}((blockedrange([1, 2]), blockedrange(1:2)))
173+
174+
B = Eye((blockedrange([1, 2]),))
175+
@test B[Block(2, 2)] == Matrix(I, 2, 2)
176+
177+
C = Eye((blockedrange([1, 2, 2]), blockedrange([2, 2])))
178+
@test C[Block(2, 2)] == [0 0; 1.0 0]
179+
180+
U = UpperTriangular(Ones((blockedrange([1, 2]), blockedrange([2, 1]))))
167181

168182
@test stringmime("text/plain", A) == "5-element Fill{$Int, 1, Tuple{BlockedUnitRange{Vector{$Int}}}} with indices 1:1:5, with entries equal to 2"
169183
@test stringmime("text/plain", B) == "3×3 Diagonal{Float64, Ones{Float64, 1, Tuple{BlockedUnitRange{Vector{$Int}}}}} with indices 1:1:3×1:1:3"
@@ -173,8 +187,8 @@ end
173187
# This in theory can be dropped because `view` returns the block, but we keep in case needed
174188
a = BlockArray(randn(6), 1:3)
175189
fill!(bview(a, Block(2)), 2)
176-
@test view(a, Block(2)) == [2,2]
177-
f = mortar([Fill(1,2), Fill(2,3)])
190+
@test view(a, Block(2)) == [2, 2]
191+
f = mortar([Fill(1, 2), Fill(2, 3)])
178192
@test FillArrays.getindex_value(bview(f, Block(2))) == 2
179193
end
180194
end

0 commit comments

Comments
 (0)