Skip to content

Commit dcf7c5d

Browse files
committed
Update bidirectional_pattern
1 parent c1ee0d4 commit dcf7c5d

3 files changed

Lines changed: 61 additions & 28 deletions

File tree

src/graph.jl

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,33 +94,44 @@ function Base.getindex(S::SparsityPatternCSC, i0::Integer, i1::Integer)
9494
end
9595

9696
"""
97-
bidirectional_pattern(A::AbstractMatrix; symmetric_pattern::Bool)
97+
bidirectional_pattern(A::AbstractMatrix; symmetric_pattern::Bool=false)
9898
9999
Return a [`SparsityPatternCSC`](@ref) corresponding to the matrix `[0 Aᵀ; A 0]`, with a minimum of allocations.
100100
"""
101-
bidirectional_pattern(A::AbstractMatrix; symmetric_pattern::Bool) =
101+
bidirectional_pattern(A::AbstractMatrix; symmetric_pattern::Bool=false) =
102102
bidirectional_pattern(SparsityPatternCSC(SparseMatrixCSC(A)); symmetric_pattern)
103103

104-
function bidirectional_pattern(S::SparsityPatternCSC; symmetric_pattern::Bool)
104+
function bidirectional_pattern(
105+
S::SparsityPatternCSC{T}; symmetric_pattern::Bool=false
106+
) where {T<:Integer}
105107
m, n = size(S)
106108
p = m + n
107109
nnzS = nnz(S)
108-
rowval = Vector{Int}(undef, 2 * nnzS)
109-
colptr = zeros(Int, p + 1)
110+
rowval = Vector{T}(undef, 2 * nnzS)
111+
colptr = zeros(T, p + 1)
112+
edge_to_index = Vector{T}(undef, 2 * nnzS)
110113

111114
# Update rowval and colptr for the block A
112115
for i in 1:nnzS
113116
rowval[i] = S.rowval[i] + n
117+
edge_to_index[i] = i
114118
end
115119
for j in 1:n
116120
colptr[j] = S.colptr[j]
117121
end
118122

119123
# Update rowval and colptr for the block Aᵀ
120124
if symmetric_pattern
125+
# Use colptr[n+1:n+m] to store the offsets during the update of edge_to_index
126+
offsets = colptr
127+
121128
# We use the sparsity pattern of A for Aᵀ
122-
for i in 1:nnzS
123-
rowval[nnzS + i] = S.rowval[i]
129+
for k in 1:nnzS
130+
r = S.rowval[k]
131+
rowval[nnzS + k] = r
132+
pos = S.colptr[r] + offsets[n + r]
133+
edge_to_index[nnzS + pos] = edge_to_index[k]
134+
offsets[n + r] += 1
124135
end
125136
# m and n are identical because symmetric_pattern is true
126137
for j in 1:m
@@ -147,6 +158,7 @@ function bidirectional_pattern(S::SparsityPatternCSC; symmetric_pattern::Bool)
147158
i = S.rowval[index]
148159
pos = colptr[n + i]
149160
rowval[nnzS + pos] = j
161+
edge_to_index[nnzS + pos] = edge_to_index[index]
150162
colptr[n + i] += 1
151163
end
152164
end
@@ -159,12 +171,10 @@ function bidirectional_pattern(S::SparsityPatternCSC; symmetric_pattern::Bool)
159171
end
160172

161173
# Create the SparsityPatternCSC of the augmented adjacency matrix
162-
S_and_Sᵀ = SparsityPatternCSC{Int}(p, p, colptr, rowval)
163-
return S_and_Sᵀ
174+
S_and_Sᵀ = SparsityPatternCSC{T}(p, p, colptr, rowval)
175+
return S_and_Sᵀ, edge_to_index
164176
end
165177

166-
# Note that we don't need to do that for bicoloring,
167-
# we can build that in the same time than the transposed sparsity pattern of A
168178
function build_edge_to_index(S::SparsityPatternCSC{T}) where {T<:Integer}
169179
# edge_to_index gives an index for each edge
170180
edge_to_index = Vector{T}(undef, nnz(S))
@@ -221,11 +231,27 @@ struct AdjacencyGraph{T,has_diagonal}
221231
vertex_buffer::Vector{T}
222232
end
223233

224-
function AdjacencyGraph(S::SparsityPatternCSC{T}; has_diagonal::Bool=true) where {T}
225-
edge_to_index, vertex_buffer = build_edge_to_index(S)
234+
function AdjacencyGraph(
235+
S::SparsityPatternCSC{T},
236+
edge_to_index::Vector{T},
237+
vertex_buffer::Vector{T};
238+
has_diagonal::Bool=true,
239+
) where {T}
226240
return AdjacencyGraph{T,has_diagonal}(S, edge_to_index, vertex_buffer)
227241
end
228242

243+
function AdjacencyGraph(
244+
S::SparsityPatternCSC{T}, edge_to_index::Vector{T}; has_diagonal::Bool=true
245+
) where {T}
246+
vertex_buffer = Vector{Int}(undef, S.n)
247+
return AdjacencyGraph(S, edge_to_index, vertex_buffer; has_diagonal)
248+
end
249+
250+
function AdjacencyGraph(S::SparsityPatternCSC; has_diagonal::Bool=true)
251+
edge_to_index, vertex_buffer = build_edge_to_index(S)
252+
return AdjacencyGraph(S, edge_to_index, vertex_buffer; has_diagonal)
253+
end
254+
229255
function AdjacencyGraph(A::SparseMatrixCSC; has_diagonal::Bool=true)
230256
return AdjacencyGraph(SparsityPatternCSC(A); has_diagonal)
231257
end
@@ -248,8 +274,9 @@ end
248274

249275
function neighbors_with_edge_indices(g::AdjacencyGraph, v::Integer)
250276
S = pattern(g)
251-
neighbors_v = view(rowvals(S), nzrange(S, v))
252-
edges_indices_v = view(edge_indices(g), nzrange(S, v))
277+
range_v = nzrange(S, v)
278+
neighbors_v = view(rowvals(S), range_v)
279+
edges_indices_v = view(edge_indices(g), range_v)
253280
return zip(neighbors_v, edges_indices_v)
254281
end
255282

@@ -328,7 +355,7 @@ When `symmetric_pattern` is `true`, this construction is more efficient.
328355
329356
> [_What Color Is Your Jacobian? SparsityPatternCSC Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005)
330357
"""
331-
struct BipartiteGraph{T<:Integer}
358+
struct BipartiteGraph{T}
332359
S1::SparsityPatternCSC{T}
333360
S2::SparsityPatternCSC{T}
334361
end

src/interface.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ function _coloring(
265265
decompression_eltype::Type,
266266
symmetric_pattern::Bool,
267267
)
268-
ag = AdjacencyGraph(A)
268+
ag = AdjacencyGraph(A; has_diagonal=true)
269269
color, star_set = star_coloring(ag, algo.order, algo.postprocessing)
270270
if speed_setting isa WithResult
271271
return StarSetColoringResult(A, ag, color, star_set)
@@ -282,7 +282,7 @@ function _coloring(
282282
decompression_eltype::Type{R},
283283
symmetric_pattern::Bool,
284284
) where {R}
285-
ag = AdjacencyGraph(A)
285+
ag = AdjacencyGraph(A; has_diagonal=true)
286286
color, tree_set = acyclic_coloring(ag, algo.order, algo.postprocessing)
287287
if speed_setting isa WithResult
288288
return TreeSetColoringResult(A, ag, color, tree_set, R)
@@ -299,8 +299,8 @@ function _coloring(
299299
decompression_eltype::Type{R},
300300
symmetric_pattern::Bool,
301301
) where {R}
302-
A_and_Aᵀ = bidirectional_pattern(A; symmetric_pattern)
303-
ag = AdjacencyGraph(A_and_Aᵀ; has_diagonal=false)
302+
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
303+
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
304304
color, star_set = star_coloring(ag, algo.order, algo.postprocessing)
305305
if speed_setting isa WithResult
306306
symmetric_result = StarSetColoringResult(A_and_Aᵀ, ag, color, star_set)
@@ -319,8 +319,8 @@ function _coloring(
319319
decompression_eltype::Type{R},
320320
symmetric_pattern::Bool,
321321
) where {R}
322-
A_and_Aᵀ = bidirectional_pattern(A; symmetric_pattern)
323-
ag = AdjacencyGraph(A_and_Aᵀ; has_diagonal=false)
322+
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
323+
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
324324
color, tree_set = acyclic_coloring(ag, algo.order, algo.postprocessing)
325325
if speed_setting isa WithResult
326326
symmetric_result = TreeSetColoringResult(A_and_Aᵀ, ag, color, tree_set, R)

test/graph.jl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,27 @@ using Test
2727
end
2828
end
2929
@testset "Bidirectional" begin
30-
@test all(1:1000) do _
30+
@testset "symmetric_pattern = false" begin
3131
m, n = rand(100:1000), rand(100:1000)
3232
p = 0.05 * rand()
3333
A = sprand(Bool, m, n, p)
3434
A_and_Aᵀ = [spzeros(Bool, n, n) transpose(A); A spzeros(Bool, m, m)]
35-
S_and_Sᵀ = bidirectional_pattern(A; symmetric_pattern=false)
36-
S_and_Sᵀ.colptr == A_and_Aᵀ.colptr && S_and_Sᵀ.rowval == A_and_Aᵀ.rowval
35+
S_and_Sᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern=false)
36+
@test S_and_Sᵀ.colptr == A_and_Aᵀ.colptr
37+
@test S_and_Sᵀ.rowval == A_and_Aᵀ.rowval
38+
M = SparseMatrixCSC(m+n, m+n, S_and_Sᵀ.colptr, S_and_Sᵀ.rowval, edge_to_index)
39+
@test issymmetric(M)
3740
end
38-
@test all(1:1000) do _
41+
@testset "symmetric_pattern = true" begin
3942
m = rand(100:1000)
4043
p = 0.05 * rand()
4144
A = sparse(Symmetric(sprand(Bool, m, m, p)))
4245
A_and_Aᵀ = [spzeros(Bool, m, m) transpose(A); A spzeros(Bool, m, m)]
43-
S_and_Sᵀ = bidirectional_pattern(A; symmetric_pattern=true)
44-
S_and_Sᵀ.colptr == A_and_Aᵀ.colptr && S_and_Sᵀ.rowval == A_and_Aᵀ.rowval
46+
S_and_Sᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern=true)
47+
@test S_and_Sᵀ.colptr == A_and_Aᵀ.colptr
48+
@test S_and_Sᵀ.rowval == A_and_Aᵀ.rowval
49+
M = SparseMatrixCSC(2*m, 2*m, S_and_Sᵀ.colptr, S_and_Sᵀ.rowval, edge_to_index)
50+
@test issymmetric(M)
4551
end
4652
end
4753
@testset "size" begin

0 commit comments

Comments
 (0)