Skip to content

Commit 6ae6588

Browse files
committed
Added BlockSkylineMatrix–{,Bi,Tri,SymTri}Diagonal arithmetic (fixes #57)
1 parent 29cdfb6 commit 6ae6588

File tree

3 files changed

+176
-17
lines changed

3 files changed

+176
-17
lines changed

src/BlockSkylineMatrix.jl

Lines changed: 132 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct BlockSkylineSizes{BS<:NTuple{2,AbstractUnitRange{Int}}, LL<:AbstractVecto
5252
u::UU
5353
end
5454

55-
const BlockBandedSizes = BlockSkylineSizes{NTuple{2,BlockedUnitRange{Vector{Int}}}, Fill{Int,1,Tuple{OneTo{Int}}}, Fill{Int,1,Tuple{OneTo{Int}}},
55+
const BlockBandedSizes = BlockSkylineSizes{NTuple{2,BlockedUnitRange{Vector{Int}}}, Fill{Int,1,Tuple{OneTo{Int}}}, Fill{Int,1,Tuple{OneTo{Int}}},
5656
BandedMatrix{Int,Matrix{Int},OneTo{Int}}, Vector{Int}}
5757

5858

@@ -247,7 +247,7 @@ BlockBandedMatrix(A::AbstractMatrix) = convert(BlockBandedMatrix, A)
247247
similar(A::BlockSkylineMatrix, T::Type=eltype(A), bs::BlockSkylineSizes=A.block_sizes) =
248248
BlockSkylineMatrix{T}(undef, bs)
249249

250-
axes(A::BlockSkylineMatrix) = A.block_sizes.axes
250+
axes(A::BlockSkylineMatrix) = A.block_sizes.axes
251251

252252
################################
253253
# BlockSkylineMatrix Interface #
@@ -390,7 +390,7 @@ const BlockBandedBlock{T} = SubArray{T,2,<:BlockSkylineMatrix,<:Tuple{<:BlockSli
390390

391391

392392
# gives the columns of parent(V).data that encode the block
393-
_parent_blocks(V::BlockBandedBlock)::Tuple{Int,Int} =
393+
_parent_blocks(V::BlockBandedBlock)::Tuple{Int,Int} =
394394
first(first(parentindices(V)).block.n),first(last(parentindices(V)).block.n)
395395

396396
######################################
@@ -437,3 +437,132 @@ end
437437
throw(BandError(A, J-K))
438438
end
439439
end
440+
441+
"""
442+
copy_accommodating_diagonals(A::BlockSkylineMatrix, diagonals::UnitRange{<:Integer})
443+
444+
Return copy of `A`, ensuring blocks are present covering the
445+
`diagonals` as well.
446+
"""
447+
function copy_accommodating_diagonals(A::BlockSkylineMatrix, diagonals::UnitRange{<:Integer}, ::Type{T}=eltype(A)) where T
448+
checksquareblocks(A)
449+
bs = A.block_sizes
450+
l,u = bs.l,bs.u
451+
ax = first(bs.axes)
452+
453+
if 0 diagonals
454+
l = max.(l, 0)
455+
u = max.(u, 0)
456+
end
457+
458+
for d = extrema(diagonals)
459+
d == 0 && continue # Already taken care of above
460+
v = d > 0 ? u : l
461+
# The j:th element of rows is the row index which the diagonal
462+
# d covers in the j:th column.
463+
rows = clamp.(ax .- d, 1, last(ax))
464+
for (j,i) in enumerate(rows)
465+
# First we find which block the j:th element of the main
466+
# diagonal would occupy.
467+
md_block = findfirst((j), ax.lasts)
468+
469+
# Next we find which block covers row i
470+
d_block = findfirst((i), ax.lasts)
471+
472+
# Finally, we increase the block-bandwidth as necessary
473+
v[md_block] = max(v[md_block], abs(d_block-md_block))
474+
end
475+
end
476+
477+
BlockSkylineMatrix{T}(A, BlockSkylineSizes((ax,ax), l, u))
478+
end
479+
480+
for op in (:-, :+)
481+
@eval begin
482+
function $op(A::BlockSkylineMatrix, D::Diagonal)
483+
B = copy_accommodating_diagonals(A, 0:0, Base._return_type(+, Tuple{eltype(A), eltype(D)}))
484+
@inbounds for i in axes(A, 1)
485+
B[i,i] = $op(B[i,i], D.diag[i])
486+
end
487+
B
488+
end
489+
function $op(D::Diagonal, A::BlockSkylineMatrix)
490+
B = copy_accommodating_diagonals($op(A), 0:0, Base._return_type(+, Tuple{eltype(A), eltype(D)}))
491+
@inbounds for i in axes(A, 1)
492+
B[i,i] += D.diag[i]
493+
end
494+
B
495+
end
496+
497+
function $op(A::BlockSkylineMatrix, Bd::Bidiagonal)
498+
B = copy_accommodating_diagonals(A, Bd.uplo == 'U' ? (0:1) : (-1:0),
499+
Base._return_type(+, Tuple{eltype(A), eltype(Bd)}))
500+
@inbounds for i in axes(A, 1)
501+
B[i,i] = $op(B[i,i], Bd.dv[i])
502+
end
503+
@inbounds for i in 1:size(A, 1)-1
504+
Bd.uplo == 'U' && (B[i,i+1] = $op(B[i,i+1], Bd.ev[i]))
505+
Bd.uplo == 'L' && (B[i+1,i] = $op(B[i+1,i], Bd.ev[i]))
506+
end
507+
B
508+
end
509+
function $op(Bd::Bidiagonal, A::BlockSkylineMatrix)
510+
B = copy_accommodating_diagonals($op(A), Bd.uplo == 'U' ? (0:1) : (-1:0),
511+
Base._return_type(+, Tuple{eltype(A), eltype(Bd)}))
512+
@inbounds for i in axes(A, 1)
513+
B[i,i] += Bd.dv[i]
514+
end
515+
@inbounds for i in 1:size(A, 1)-1
516+
Bd.uplo == 'U' && (B[i,i+1] += Bd.ev[i])
517+
Bd.uplo == 'L' && (B[i+1,i] += Bd.ev[i])
518+
end
519+
B
520+
end
521+
522+
function $op(A::BlockSkylineMatrix, T::Tridiagonal)
523+
B = copy_accommodating_diagonals(A, -1:1, Base._return_type(+, Tuple{eltype(A), eltype(T)}))
524+
@inbounds for i in axes(A, 1)
525+
B[i,i] = $op(B[i,i], T.d[i])
526+
end
527+
@inbounds for i in 1:size(A, 1)-1
528+
B[i,i+1] = $op(B[i,i+1], T.du[i])
529+
B[i+1,i] = $op(B[i+1,i], T.dl[i])
530+
end
531+
B
532+
end
533+
function $op(T::Tridiagonal, A::BlockSkylineMatrix)
534+
B = copy_accommodating_diagonals($op(A), -1:1, Base._return_type(+, Tuple{eltype(A), eltype(T)}))
535+
@inbounds for i in axes(A, 1)
536+
B[i,i] += T.d[i]
537+
end
538+
@inbounds for i in 1:size(A, 1)-1
539+
B[i,i+1] += T.du[i]
540+
B[i+1,i] += T.dl[i]
541+
end
542+
B
543+
end
544+
545+
function $op(A::BlockSkylineMatrix, T::SymTridiagonal)
546+
B = copy_accommodating_diagonals(A, -1:1, Base._return_type(+, Tuple{eltype(A), eltype(T)}))
547+
@inbounds for i in axes(A, 1)
548+
B[i,i] = $op(B[i,i], T.dv[i])
549+
end
550+
@inbounds for i in 1:size(A, 1)-1
551+
B[i,i+1] = $op(B[i,i+1], T.ev[i])
552+
B[i+1,i] = $op(B[i+1,i], T.ev[i])
553+
end
554+
B
555+
end
556+
function $op(T::SymTridiagonal, A::BlockSkylineMatrix)
557+
B = copy_accommodating_diagonals($op(A), -1:1, Base._return_type(+, Tuple{eltype(A), eltype(T)}))
558+
@inbounds for i in axes(A, 1)
559+
B[i,i] += T.dv[i]
560+
end
561+
@inbounds for i in 1:size(A, 1)-1
562+
B[i,i+1] += T.ev[i]
563+
B[i+1,i] += T.ev[i]
564+
end
565+
B
566+
end
567+
end
568+
end

src/interfaceimpl.jl

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,3 @@ for op in (:-, :+)
110110
end
111111
end
112112
end
113-
114-
function replace_in_print_matrix(A::BlockDiagonal, i::Integer, j::Integer, s::AbstractString)
115-
bi = findblockindex.(axes(A), (i,j))
116-
I,J = block.(bi)
117-
i,j = blockindex.(bi)
118-
Int(J-I) == 0 ? s : Base.replace_with_centered_mark(s)
119-
end
120-
121-
function replace_in_print_matrix(A::BlockTridiagonal, i::Integer, j::Integer, s::AbstractString)
122-
bi = findblockindex.(axes(A), (i,j))
123-
I,J = block.(bi)
124-
i,j = blockindex.(bi)
125-
-1 Int(J-I)  1 ? s : Base.replace_with_centered_mark(s)
126-
end

test/test_blockskyline.jl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,48 @@ Random.seed!(0)
104104
@test Matrix(AC) == Matrix(A) + Matrix(C)
105105
@test blockisequal(axes(AC),axes(C))
106106
end
107+
108+
@testset "BlockSkylineMatrix arithmetic" begin
109+
t = Int
110+
rows = cols = 1:4
111+
N = sum(rows)
112+
D = Diagonal(ones(t, N))
113+
Bu = Bidiagonal(ones(t, N), 2ones(t, N-1), 'U')
114+
Bl = Bidiagonal(ones(t, N), 2ones(t, N-1), 'L')
115+
T = Tridiagonal(ones(t, N-1), 2ones(t, N), 3ones(t, N-1))
116+
ST = SymTridiagonal(ones(t, N), 2ones(t, N-1))
117+
118+
function check_blockskylinematrix_arithmetic(A, op, B, (l,u))
119+
C = op(A, B)
120+
Cdense = op(Matrix(A), Matrix(B))
121+
@test C == Cdense
122+
123+
bs = (A isa BlockSkylineMatrix ? A : B).block_sizes
124+
expl = max.(l, bs.l)
125+
expu = max.(u, bs.u)
126+
127+
Cbs = C.block_sizes
128+
@test all(Cbs.l .== expl)
129+
@test all(Cbs.u .== expu)
130+
end
131+
132+
for (l,u) = [([0,0,0,0],[0,0,0,0]),
133+
([-1,-1,-1,-1],[1,2,2,2]),
134+
([-1,-2,-2,-2],[1,1,2,2]),
135+
([2,2,1,1],[-1,-1,-1,-1]),
136+
([2,2,1,1],[-2,-2,-2,-1])]
137+
M = BlockSkylineMatrix{t}(undef, rows, cols, (l,u))
138+
M.data .= 1
139+
for (A,expected_bws) = [(D, ([0,0,0,0],[0,0,0,0])),
140+
(Bu, ([0,0,0,0],[0,1,1,1])),
141+
(Bl, ([1,1,1,0],[0,0,0,0])),
142+
(T, ([1,1,1,0],[0,1,1,1])),
143+
(ST, ([1,1,1,0],[0,1,1,1]))]
144+
for op = (+, -)
145+
check_blockskylinematrix_arithmetic(M, op, A, expected_bws)
146+
check_blockskylinematrix_arithmetic(A, op, M, expected_bws)
147+
end
148+
end
149+
end
150+
end
107151
end

0 commit comments

Comments
 (0)