Skip to content

Commit 1b69942

Browse files
Merge pull request #14 from huanglangwen/bbbmatrix
add findstructralnz support for BandedMatrix, BlockBandedMatrix and BandedBlockBandedMatrix
2 parents c8513cb + 380977b commit 1b69942

File tree

3 files changed

+246
-13
lines changed

3 files changed

+246
-13
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ julia = "1"
1414
LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800"
1515
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1616
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
17+
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
18+
BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
1719

1820
[targets]
19-
test = ["Test", "LabelledArrays", "StaticArrays"]
21+
test = ["Test", "LabelledArrays", "StaticArrays","BandedMatrices","BlockBandedMatrices"]

src/ArrayInterface.jl

Lines changed: 208 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,134 @@ struct BidiagonalIndex <: MatrixIndex
104104
end
105105

106106
struct TridiagonalIndex <: MatrixIndex
107-
count::Int
107+
count::Int#count==nsize+nsize-1+nsize-1
108108
nsize::Int
109109
isrow::Bool
110110
end
111111

112+
struct BandedMatrixIndex <: MatrixIndex
113+
count::Int
114+
rowsize::Int
115+
colsize::Int
116+
bandinds::Array{Int,1}
117+
bandsizes::Array{Int,1}
118+
isrow::Bool
119+
end
120+
121+
function _bandsize(bandind,rowsize,colsize)
122+
-(rowsize-1) <= bandind <= colsize-1 || throw(ErrorException("Invalid Bandind"))
123+
if (bandind*(colsize-rowsize)>0) & (abs(bandind)<=abs(colsize-rowsize))
124+
return min(rowsize,colsize)
125+
elseif bandind*(colsize-rowsize)<=0
126+
return min(rowsize,colsize)-abs(bandind)
127+
else
128+
return min(rowsize,colsize)-abs(bandind)+abs(colsize-rowsize)
129+
end
130+
end
131+
132+
function BandedMatrixIndex(rowsize,colsize,lowerbandwidth,upperbandwidth,isrow)
133+
upperbandwidth>-lowerbandwidth || throw(ErrorException("Invalid Bandwidths"))
134+
bandinds=upperbandwidth:-1:-lowerbandwidth
135+
bandsizes=[_bandsize(band,rowsize,colsize) for band in bandinds]
136+
BandedMatrixIndex(sum(bandsizes),rowsize,colsize,bandinds,bandsizes,isrow)
137+
end
138+
139+
struct BlockBandedMatrixIndex <: MatrixIndex
140+
count::Int
141+
refinds::Array{Int,1}
142+
refcoords::Array{Int,1}#storing col or row inds at ref points
143+
isrow::Bool
144+
end
145+
146+
function BlockBandedMatrixIndex(nrowblock,ncolblock,rowsizes,colsizes,l,u)
147+
blockrowind=BandedMatrixIndex(nrowblock,ncolblock,l,u,true)
148+
blockcolind=BandedMatrixIndex(nrowblock,ncolblock,l,u,false)
149+
sortedinds=sort([(blockrowind[i],blockcolind[i]) for i in 1:length(blockrowind)],by=x->x[1])
150+
sort!(sortedinds,by=x->x[2],alg=InsertionSort)#stable sort keeps the second index in order
151+
refinds=Array{Int,1}()
152+
refrowcoords=Array{Int,1}()
153+
refcolcoords=Array{Int,1}()
154+
rowheights=cumsum(pushfirst!(copy(rowsizes),1))
155+
blockheight=0
156+
blockrow=1
157+
blockcol=1
158+
currenti=1
159+
lastrowind=sortedinds[1][1]-1
160+
lastcolind=sortedinds[1][2]
161+
for ind in sortedinds
162+
rowind,colind=ind
163+
if colind==lastcolind
164+
if rowind>lastrowind
165+
blockheight+=rowsizes[rowind]
166+
end
167+
else
168+
for j in blockcol:blockcol+colsizes[lastcolind]-1
169+
push!(refinds,currenti)
170+
push!(refrowcoords,blockrow)
171+
push!(refcolcoords,j)
172+
currenti+=blockheight
173+
end
174+
blockcol+=colsizes[lastcolind]
175+
blockrow=rowheights[rowind]
176+
blockheight=rowsizes[rowind]
177+
end
178+
lastcolind=colind
179+
lastrowind=rowind
180+
end
181+
for j in blockcol:blockcol+colsizes[lastcolind]-1
182+
push!(refinds,currenti)
183+
push!(refrowcoords,blockrow)
184+
push!(refcolcoords,j)
185+
currenti+=blockheight
186+
end
187+
push!(refinds,currenti)#guard
188+
push!(refrowcoords,-1)
189+
push!(refcolcoords,-1)
190+
rowindobj=BlockBandedMatrixIndex(currenti-1,refinds,refrowcoords,true)
191+
colindobj=BlockBandedMatrixIndex(currenti-1,refinds,refcolcoords,false)
192+
rowindobj,colindobj
193+
end
194+
195+
struct BandedBlockBandedMatrixIndex <: MatrixIndex
196+
count::Int
197+
refinds::Array{Int,1}
198+
refcoords::Array{Int,1}#storing col or row inds at ref points
199+
reflocalinds::Array{BandedMatrixIndex,1}
200+
isrow::Bool
201+
end
202+
203+
function BandedBlockBandedMatrixIndex(nrowblock,ncolblock,rowsizes,colsizes,l,u,lambda,mu)
204+
blockrowind=BandedMatrixIndex(nrowblock,ncolblock,l,u,true)
205+
blockcolind=BandedMatrixIndex(nrowblock,ncolblock,l,u,false)
206+
sortedinds=sort([(blockrowind[i],blockcolind[i]) for i in 1:length(blockrowind)],by=x->x[1])
207+
sort!(sortedinds,by=x->x[2],alg=InsertionSort)#stable sort keeps the second index in order
208+
rowheights=cumsum(pushfirst!(copy(rowsizes),1))
209+
colwidths=cumsum(pushfirst!(copy(colsizes),1))
210+
currenti=1
211+
refinds=Array{Int,1}()
212+
refrowcoords=Array{Int,1}()
213+
refcolcoords=Array{Int,1}()
214+
reflocalrowinds=Array{BandedMatrixIndex,1}()
215+
reflocalcolinds=Array{BandedMatrixIndex,1}()
216+
for ind in sortedinds
217+
rowind,colind=ind
218+
localrowind=BandedMatrixIndex(rowsizes[rowind],colsizes[colind],lambda,mu,true)
219+
localcolind=BandedMatrixIndex(rowsizes[rowind],colsizes[colind],lambda,mu,false)
220+
push!(refinds,currenti)
221+
push!(refrowcoords,rowheights[rowind])
222+
push!(refcolcoords,colwidths[colind])
223+
push!(reflocalrowinds,localrowind)
224+
push!(reflocalcolinds,localcolind)
225+
currenti+=localrowind.count
226+
end
227+
push!(refinds,currenti)
228+
push!(refrowcoords,-1)
229+
push!(refcolcoords,-1)
230+
rowindobj=BandedBlockBandedMatrixIndex(currenti-1,refinds,refrowcoords,reflocalrowinds,true)
231+
colindobj=BandedBlockBandedMatrixIndex(currenti-1,refinds,refcolcoords,reflocalcolinds,false)
232+
rowindobj,colindobj
233+
end
234+
112235
Base.firstindex(ind::MatrixIndex)=1
113236
Base.lastindex(ind::MatrixIndex)=ind.count
114237
Base.length(ind::MatrixIndex)=ind.count
@@ -135,6 +258,49 @@ function Base.getindex(ind::TridiagonalIndex,i::Int)
135258
end
136259
end
137260

261+
function Base.getindex(ind::BandedMatrixIndex,i::Int)
262+
1 <= i <= ind.count || throw(BoundsError(ind, i))
263+
_i=i
264+
p=1
265+
while _i-ind.bandsizes[p]>0
266+
_i-=ind.bandsizes[p]
267+
p+=1
268+
end
269+
bandind=ind.bandinds[p]
270+
startfromone=!xor(ind.isrow,(bandind>0))
271+
if startfromone
272+
return _i
273+
else
274+
return _i+abs(bandind)
275+
end
276+
end
277+
278+
function Base.getindex(ind::BlockBandedMatrixIndex,i::Int)
279+
1 <= i <= ind.count || throw(BoundsError(ind, i))
280+
p=1
281+
while i-ind.refinds[p]>=0
282+
p+=1
283+
end
284+
p-=1
285+
_i=i-ind.refinds[p]
286+
if ind.isrow
287+
return ind.refcoords[p]+_i
288+
else
289+
return ind.refcoords[p]
290+
end
291+
end
292+
293+
function Base.getindex(ind::BandedBlockBandedMatrixIndex,i::Int)
294+
1 <= i <= ind.count || throw(BoundsError(ind, i))
295+
p=1
296+
while i-ind.refinds[p]>=0
297+
p+=1
298+
end
299+
p-=1
300+
_i=i-ind.refinds[p]+1
301+
ind.reflocalinds[p][_i]+ind.refcoords[p]-1
302+
end
303+
138304
function findstructralnz(x::Bidiagonal)
139305
n=size(x,1)
140306
isup= x.uplo=='U' ? true : false
@@ -225,28 +391,58 @@ function __init__()
225391
end
226392

227393
@require BandedMatrices="aae01518-5342-5314-be14-df237901396f" begin
394+
function findstructralnz(x::BandedMatrices.BandedMatrix)
395+
l,u=BandedMatrices.bandwidths(x)
396+
rowsize,colsize=size(x)
397+
rowind=BandedMatrixIndex(rowsize,colsize,l,u,true)
398+
colind=BandedMatrixIndex(rowsize,colsize,l,u,false)
399+
(rowind,colind)
400+
end
401+
402+
has_sparsestruct(::Type{<:BandedMatrices.BandedMatrix}) = true
228403
is_structured(::Type{<:BandedMatrices.BandedMatrix}) = true
229404
fast_matrix_colors(::Type{<:BandedMatrices.BandedMatrix}) = true
230405

231406
function matrix_colors(A::BandedMatrices.BandedMatrix)
232-
u,l=bandwidths(A)
407+
l,u=BandedMatrices.bandwidths(A)
233408
width=u+l+1
234409
_cycle(1:width,size(A,2))
235410
end
236411

237412
end
238413

239-
@require BlockBandedMatrices="aae01518-5342-5314-be14-df237901396f" begin
240-
is_structured(::Type{<:BandedMatrices.BlockBandedMatrix}) = true
241-
is_structured(::Type{<:BandedMatrices.BandedBlockBandedMatrix}) = true
414+
@require BlockBandedMatrices="ffab5731-97b5-5995-9138-79e8c1846df0" begin
415+
function findstructralnz(x::BlockBandedMatrices.BlockBandedMatrix)
416+
l,u=BlockBandedMatrices.blockbandwidths(x)
417+
nrowblock=BlockBandedMatrices.nblocks(x,1)
418+
ncolblock=BlockBandedMatrices.nblocks(x,2)
419+
rowsizes=[BlockBandedMatrices.blocksize(x,(i,1))[1] for i in 1:nrowblock]
420+
colsizes=[BlockBandedMatrices.blocksize(x,(1,i))[2] for i in 1:ncolblock]
421+
BlockBandedMatrixIndex(nrowblock,ncolblock,rowsizes,colsizes,l,u)
422+
end
423+
424+
function findstructralnz(x::BlockBandedMatrices.BandedBlockBandedMatrix)
425+
l,u=BlockBandedMatrices.blockbandwidths(x)
426+
lambda,mu=BlockBandedMatrices.subblockbandwidths(x)
427+
nrowblock=BlockBandedMatrices.nblocks(x,1)
428+
ncolblock=BlockBandedMatrices.nblocks(x,2)
429+
rowsizes=[BlockBandedMatrices.blocksize(x,(i,1))[1] for i in 1:nrowblock]
430+
colsizes=[BlockBandedMatrices.blocksize(x,(1,i))[2] for i in 1:ncolblock]
431+
BandedBlockBandedMatrixIndex(nrowblock,ncolblock,rowsizes,colsizes,l,u,lambda,mu)
432+
end
433+
434+
has_sparsestruct(::Type{<:BlockBandedMatrices.BlockBandedMatrix}) = true
435+
has_sparsestruct(::Type{<:BlockBandedMatrices.BandedBlockBandedMatrix}) = true
436+
is_structured(::Type{<:BlockBandedMatrices.BlockBandedMatrix}) = true
437+
is_structured(::Type{<:BlockBandedMatrices.BandedBlockBandedMatrix}) = true
242438
fast_matrix_colors(::Type{<:BlockBandedMatrices.BlockBandedMatrix}) = true
243439
fast_matrix_colors(::Type{<:BlockBandedMatrices.BandedBlockBandedMatrix}) = true
244440

245441
function matrix_colors(A::BlockBandedMatrices.BlockBandedMatrix)
246-
l,u=blockbandwidths(A)
442+
l,u=BlockBandedMatrices.blockbandwidths(A)
247443
blockwidth=l+u+1
248-
nblock=nblocks(A,2)
249-
cols=[blocksize(A,(1,i))[2] for i in 1:nblock]
444+
nblock=BlockBandedMatrices.nblocks(A,2)
445+
cols=[BlockBandedMatrices.blocksize(A,(1,i))[2] for i in 1:nblock]
250446
blockcolors=_cycle(1:blockwidth,nblock)
251447
#the reserved number of colors of a block is the maximum length of columns of blocks with the same block color
252448
ncolors=[maximum(cols[i:blockwidth:nblock]) for i in 1:blockwidth]
@@ -257,12 +453,12 @@ function __init__()
257453
end
258454

259455
function matrix_colors(A::BlockBandedMatrices.BandedBlockBandedMatrix)
260-
l,u=blockbandwidths(A)
261-
lambda,mu=subblockbandwidths(A)
456+
l,u=BlockBandedMatrices.blockbandwidths(A)
457+
lambda,mu=BlockBandedMatrices.subblockbandwidths(A)
262458
blockwidth=l+u+1
263459
subblockwidth=lambda+mu+1
264-
nblock=nblocks(A,2)
265-
cols=[blocksize(A,(1,i))[2] for i in 1:nblock]
460+
nblock=BlockBandedMatrices.nblocks(A,2)
461+
cols=[BlockBandedMatrices.blocksize(A,(1,i))[2] for i in 1:nblock]
266462
blockcolors=_cycle(1:blockwidth,nblock)
267463
#the reserved number of colors of a block is the min of subblockwidth and the largest length of columns of blocks with the same block color
268464
ncolors=[min(subblockwidth,maximum(cols[i:blockwidth:nblock])) for i in 1:min(blockwidth,nblock)]

test/runtests.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,38 @@ Sp=sparse([1,2,3],[1,2,3],[1,2,3])
3737
@test has_sparsestruct(Sp)
3838
rowind,colind=findstructralnz(Sp)
3939
@test [Tri[rowind[i],colind[i]] for i in 1:length(rowind)]==[1,2,3]
40+
41+
using BandedMatrices
42+
43+
B=BandedMatrix(Ones(5,5), (-1,2))
44+
B[band(1)].=[1,2,3,4]
45+
B[band(2)].=[5,6,7]
46+
@test has_sparsestruct(B)
47+
rowind,colind=findstructralnz(B)
48+
@test [B[rowind[i],colind[i]] for i in 1:length(rowind)]==[5,6,7,1,2,3,4]
49+
B=BandedMatrix(Ones(4,6), (-1,2))
50+
B[band(1)].=[1,2,3,4]
51+
B[band(2)].=[5,6,7,8]
52+
rowind,colind=findstructralnz(B)
53+
@test [B[rowind[i],colind[i]] for i in 1:length(rowind)]==[5,6,7,8,1,2,3,4]
54+
55+
using BlockBandedMatrices
56+
BB=BlockBandedMatrix(Ones(10,10),([1,2,3,4],[4,3,2,1]),(1,0))
57+
BB[Block(1,1)].=[1 2 3 4]
58+
BB[Block(2,1)].=[5 6 7 8;9 10 11 12]
59+
rowind,colind=findstructralnz(BB)
60+
@test [BB[rowind[i],colind[i]] for i in 1:length(rowind)]==
61+
[1,5,9,2,6,10,3,7,11,4,8,12,
62+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,
63+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,
64+
1,1,1,1,1]
65+
66+
dense=collect(Ones(8,8))
67+
for i in 1:8
68+
dense[:,i].=[1,2,3,4,5,6,7,8]
69+
end
70+
BBB=BandedBlockBandedMatrix(dense, ([4, 4] ,[4, 4]), (1, 1), (1, 1))
71+
rowind,colind=findstructralnz(BBB)
72+
@test [BBB[rowind[i],colind[i]] for i in 1:length(rowind)]==
73+
[1,2,3,1,2,3,4,2,3,4,5,6,7,5,6,7,8,6,7,8,
74+
1,2,3,1,2,3,4,2,3,4,5,6,7,5,6,7,8,6,7,8]

0 commit comments

Comments
 (0)