Skip to content

Commit 2a36a59

Browse files
committed
Take into account the comments of Guillaume
1 parent 572329d commit 2a36a59

3 files changed

Lines changed: 91 additions & 74 deletions

File tree

docs/src/dev.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ SparseMatrixColorings.structurally_orthogonal_columns
5252
SparseMatrixColorings.structurally_biorthogonal
5353
SparseMatrixColorings.substitutable_columns
5454
SparseMatrixColorings.substitutable_bidirectional
55+
SparseMatrixColorings.rank_nonzeros_from_trees
5556
SparseMatrixColorings.valid_dynamic_order
5657
```
5758

src/check.jl

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,12 @@ end
269269

270270
"""
271271
substitutable_columns(
272-
A::AbstractMatrix, order_nonzeros::AbstractMatrix, color::AbstractVector{<:Integer};
272+
A::AbstractMatrix, rank_nonzeros::AbstractMatrix, color::AbstractVector{<:Integer};
273273
verbose=false
274274
)
275275
276276
Return `true` if coloring the columns of the symmetric matrix `A` with the vector `color` results in a partition that is substitutable, and `false` otherwise.
277-
For all nonzeros `A[i, j]`, `order_nonzeros[i, j]` provides its order of recovery.
277+
For all nonzeros `A[i, j]`, `rank_nonzeros[i, j]` provides its rank of recovery.
278278
279279
A partition of the columns of a symmetric matrix `A` is _substitutable_ if, for every nonzero element `A[i, j]`, either of the following statements holds:
280280
@@ -294,7 +294,7 @@ It is equivalent to an __acyclic coloring__.
294294
"""
295295
function substitutable_columns(
296296
A::AbstractMatrix,
297-
order_nonzeros::AbstractMatrix,
297+
rank_nonzeros::AbstractMatrix,
298298
color::AbstractVector{<:Integer};
299299
verbose::Bool=false,
300300
)
@@ -308,7 +308,7 @@ function substitutable_columns(
308308
iszero(A[i, j]) && continue
309309
ci, cj = color[i], color[j]
310310
check = _substitutable_check(
311-
A, order_nonzeros; i, j, ci, cj, row_group=group, column_group=group, verbose
311+
A, rank_nonzeros; i, j, ci, cj, row_group=group, column_group=group, verbose
312312
)
313313
!check && return false
314314
end
@@ -317,12 +317,12 @@ end
317317

318318
"""
319319
substitutable_bidirectional(
320-
A::AbstractMatrix, order_nonzeros::AbstractMatrix, row_color::AbstractVector{<:Integer}, column_color::AbstractVector{<:Integer};
320+
A::AbstractMatrix, rank_nonzeros::AbstractMatrix, row_color::AbstractVector{<:Integer}, column_color::AbstractVector{<:Integer};
321321
verbose=false
322322
)
323323
324324
Return `true` if bicoloring of the matrix `A` with the vectors `row_color` and `column_color` results in a bipartition that is substitutable, and `false` otherwise.
325-
For all nonzeros `A[i, j]`, `order_nonzeros[i, j]` provides its order of recovery.
325+
For all nonzeros `A[i, j]`, `rank_nonzeros[i, j]` provides its rank of recovery.
326326
327327
A bipartition of the rows and columns of a matrix `A` is _substitutable_ if, for every nonzero element `A[i, j]`, either of the following statements holds:
328328
@@ -336,7 +336,7 @@ It is equivalent to an __acyclic bicoloring__.
336336
"""
337337
function substitutable_bidirectional(
338338
A::AbstractMatrix,
339-
order_nonzeros::AbstractMatrix,
339+
rank_nonzeros::AbstractMatrix,
340340
row_color::AbstractVector{<:Integer},
341341
column_color::AbstractVector{<:Integer};
342342
verbose::Bool=false,
@@ -350,7 +350,7 @@ function substitutable_bidirectional(
350350
iszero(A[i, j]) && continue
351351
ci, cj = row_color[i], column_color[j]
352352
check = _substitutable_check(
353-
A, order_nonzeros; i, j, ci, cj, row_group, column_group, verbose
353+
A, rank_nonzeros; i, j, ci, cj, row_group, column_group, verbose
354354
)
355355
!check && return false
356356
end
@@ -359,7 +359,7 @@ end
359359

360360
function _substitutable_check(
361361
A::AbstractMatrix,
362-
order_nonzeros::AbstractMatrix;
362+
rank_nonzeros::AbstractMatrix;
363363
i::Integer,
364364
j::Integer,
365365
ci::Integer,
@@ -368,14 +368,14 @@ function _substitutable_check(
368368
column_group::AbstractVector,
369369
verbose::Bool,
370370
)
371-
order_ij = order_nonzeros[i, j]
371+
order_ij = rank_nonzeros[i, j]
372372
k_row = 0
373373
k_column = 0
374374
if ci != 0
375375
for k in row_group[ci]
376376
(k == i) && continue
377377
if !iszero(A[k, j])
378-
order_kj = order_nonzeros[k, j]
378+
order_kj = rank_nonzeros[k, j]
379379
@assert !iszero(order_kj)
380380
if order_kj > order_ij
381381
k_row = k
@@ -387,7 +387,7 @@ function _substitutable_check(
387387
for k in column_group[cj]
388388
(k == j) && continue
389389
if !iszero(A[i, k])
390-
order_ik = order_nonzeros[i, k]
390+
order_ik = rank_nonzeros[i, k]
391391
@assert !iszero(order_ik)
392392
if order_ik > order_ij
393393
k_column = k
@@ -500,3 +500,75 @@ function valid_dynamic_order(
500500
end
501501
return true
502502
end
503+
504+
"""
505+
rank_nonzeros_from_trees(result::TreeSetColoringResult)
506+
rank_nonzeros_from_trees(result::BicoloringResult)
507+
508+
Construct a sparse matrix `rank_nonzeros` that assigns a unique recovery rank
509+
to each nonzero coefficient associated with an acyclic coloring or bicoloring.
510+
511+
For every nonzero entry `result.A[i, j]`, `rank_nonzeros[i, j]` stores a strictly positive
512+
integer representing the order in which this coefficient is recovered during the decompression.
513+
A larger value means the coefficient is recovered later.
514+
515+
This ranking is used to test substitutability (acyclicity) of colorings:
516+
for a given nonzero `result.A[i, j]`, the ranks allow one to check whether all competing
517+
nonzeros in the same row or column (within a color group) are recovered before it.
518+
"""
519+
function rank_nonzeros_from_trees end
520+
521+
function rank_nonzeros_from_trees(result::TreeSetColoringResult)
522+
(; A, ag, reverse_bfs_orders, diagonal_indices, tree_edge_indices, nt) = result
523+
(; S) = ag
524+
m, n = size(A)
525+
nnzS = nnz(S)
526+
nzval = zeros(Int, nnzS)
527+
rank_nonzeros = SparseMatrixCSC(n, n, S.colptr, S.rowval, nzval)
528+
counter = 0
529+
for i in diagonal_indices
530+
counter += 1
531+
rank_nonzeros[i, i] = counter
532+
end
533+
for k in 1:nt
534+
first = tree_edge_indices[k]
535+
last = tree_edge_indices[k + 1] - 1
536+
for pos in first:last
537+
(i, j) = reverse_bfs_orders[pos]
538+
counter += 1
539+
rank_nonzeros[i, j] = counter
540+
rank_nonzeros[j, i] = counter
541+
end
542+
end
543+
return rank_nonzeros
544+
end
545+
546+
function rank_nonzeros_from_trees(result::BicoloringResult)
547+
(; A, abg, row_color, column_color, symmetric_result, large_colptr, large_rowval) =
548+
result
549+
@assert symmetric_result isa TreeSetColoringResult
550+
(; ag, reverse_bfs_orders, tree_edge_indices, nt) = symmetric_result
551+
(; S) = ag
552+
m, n = size(A)
553+
nnzA = nnz(S) ÷ 2
554+
nzval = zeros(Int, nnzA)
555+
colptr = large_colptr[1:(n + 1)]
556+
rowval = large_rowval[1:nnzA]
557+
rowval .-= n
558+
rank_nonzeros = SparseMatrixCSC(m, n, colptr, rowval, nzval)
559+
counter = 0
560+
for k in 1:nt
561+
first = tree_edge_indices[k]
562+
last = tree_edge_indices[k + 1] - 1
563+
for pos in first:last
564+
(i, j) = reverse_bfs_orders[pos]
565+
counter += 1
566+
if i > j
567+
rank_nonzeros[i - n, j] = counter
568+
else
569+
rank_nonzeros[j - n, i] = counter
570+
end
571+
end
572+
end
573+
return rank_nonzeros
574+
end

test/utils.jl

Lines changed: 6 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7,77 +7,21 @@ using SparseMatrixColorings
77
using SparseMatrixColorings:
88
AdjacencyGraph,
99
LinearSystemColoringResult,
10-
TreeSetColoringResult,
11-
BicoloringResult,
1210
directly_recoverable_columns,
1311
matrix_versions,
1412
respectful_similar,
1513
structurally_orthogonal_columns,
1614
symmetrically_orthogonal_columns,
1715
structurally_biorthogonal,
1816
substitutable_columns,
19-
substitutable_bidirectional
17+
substitutable_bidirectional,
18+
rank_nonzeros_from_trees
2019
using Test
2120

2221
const _ALL_ORDERS = (
2322
NaturalOrder(), LargestFirst(), SmallestLast(), IncidenceDegree(), DynamicLargestFirst()
2423
)
2524

26-
function order_from_trees(result::TreeSetColoringResult)
27-
(; A, ag, reverse_bfs_orders, diagonal_indices, tree_edge_indices, nt) = result
28-
(; S) = ag
29-
m, n = size(A)
30-
nnzS = nnz(S)
31-
nzval = zeros(Int, nnzS)
32-
order_nonzeros = SparseMatrixCSC(n, n, S.colptr, S.rowval, nzval)
33-
counter = 0
34-
for i in diagonal_indices
35-
counter += 1
36-
order_nonzeros[i, i] = counter
37-
end
38-
for k in 1:nt
39-
first = tree_edge_indices[k]
40-
last = tree_edge_indices[k + 1] - 1
41-
for pos in first:last
42-
(i, j) = reverse_bfs_orders[pos]
43-
counter += 1
44-
order_nonzeros[i, j] = counter
45-
order_nonzeros[j, i] = counter
46-
end
47-
end
48-
return order_nonzeros
49-
end
50-
51-
function order_from_trees(result::BicoloringResult)
52-
(; A, abg, row_color, column_color, symmetric_result, large_colptr, large_rowval) =
53-
result
54-
@assert symmetric_result isa TreeSetColoringResult
55-
(; ag, reverse_bfs_orders, tree_edge_indices, nt) = symmetric_result
56-
(; S) = ag
57-
m, n = size(A)
58-
nnzA = nnz(S) ÷ 2
59-
nzval = zeros(Int, nnzA)
60-
colptr = large_colptr[1:(n + 1)]
61-
rowval = large_rowval[1:nnzA]
62-
rowval .-= n
63-
order_nonzeros = SparseMatrixCSC(m, n, colptr, rowval, nzval)
64-
counter = 0
65-
for k in 1:nt
66-
first = tree_edge_indices[k]
67-
last = tree_edge_indices[k + 1] - 1
68-
for pos in first:last
69-
(i, j) = reverse_bfs_orders[pos]
70-
counter += 1
71-
if i > j
72-
order_nonzeros[i - n, j] = counter
73-
else
74-
order_nonzeros[j - n, i] = counter
75-
end
76-
end
77-
end
78-
return order_nonzeros
79-
end
80-
8125
function test_coloring_decompression(
8226
A0::AbstractMatrix,
8327
problem::ColoringProblem{structure,partition},
@@ -158,8 +102,8 @@ function test_coloring_decompression(
158102
@testset "Substitutable" begin
159103
if decompression == :substitution
160104
if structure == :symmetric
161-
order_nonzeros = order_from_trees(result)
162-
@test substitutable_columns(A0, order_nonzeros, color)
105+
rank_nonzeros = rank_nonzeros_from_trees(result)
106+
@test substitutable_columns(A0, rank_nonzeros, color)
163107
end
164108
end
165109
end
@@ -305,9 +249,9 @@ function test_bicoloring_decompression(
305249

306250
if decompression == :substitution
307251
@testset "Substitutable" begin
308-
order_nonzeros = order_from_trees(result)
252+
rank_nonzeros = rank_nonzeros_from_trees(result)
309253
@test substitutable_bidirectional(
310-
A0, order_nonzeros, row_color, column_color
254+
A0, rank_nonzeros, row_color, column_color
311255
)
312256
end
313257
end

0 commit comments

Comments
 (0)