Skip to content

Commit 1582bf3

Browse files
authored
More tests (#13)
* More tests * Fix tests
1 parent d5b7873 commit 1582bf3

File tree

12 files changed

+395
-284
lines changed

12 files changed

+395
-284
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "SparseMatrixColorings"
22
uuid = "0a514795-09f3-496d-8182-132a7b665d35"
33
authors = ["Guillaume Dalle <22795598+gdalle@users.noreply.github.com>"]
4-
version = "0.3.2"
4+
version = "0.3.3"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"

docs/src/api.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ star_coloring
6969
### Testing
7070

7171
```@docs
72-
check_structurally_orthogonal_columns
73-
check_symmetrically_orthogonal_columns
72+
structurally_orthogonal_columns
73+
symmetrically_orthogonal_columns
74+
directly_recoverable_columns
7475
```

src/SparseMatrixColorings.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module SparseMatrixColorings
77

88
using ADTypes:
99
ADTypes, AbstractColoringAlgorithm, column_coloring, row_coloring, symmetric_coloring
10-
using Compat: @compat
10+
using Compat: @compat, stack
1111
using DocStringExtensions: README
1212
using LinearAlgebra:
1313
Adjoint,

src/check.jl

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
function proper_length_coloring(
2+
A::AbstractMatrix, color::AbstractVector{<:Integer}; verbose::Bool
3+
)
4+
if length(color) != size(A, 2)
5+
if verbose
6+
@warn "$(length(color)) colors provided for $(size(A, 2)) columns."
7+
end
8+
return false
9+
end
10+
return true
11+
end
12+
113
"""
2-
check_structurally_orthogonal_columns(
14+
structurally_orthogonal_columns(
315
A::AbstractMatrix, color::AbstractVector{<:Integer}
416
verbose=false
517
)
@@ -15,13 +27,10 @@ A partition of the columns of a matrix `A` is _structurally orthogonal_ if, for
1527
1628
> [_What Color Is Your Jacobian? Graph Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005)
1729
"""
18-
function check_structurally_orthogonal_columns(
30+
function structurally_orthogonal_columns(
1931
A::AbstractMatrix, color::AbstractVector{<:Integer}; verbose::Bool=false
2032
)
21-
if length(color) != size(A, 2)
22-
if verbose
23-
@warn "$(length(color)) colors provided for $(size(A, 2)) columns"
24-
end
33+
if !proper_length_coloring(A, color; verbose)
2534
return false
2635
end
2736
group = color_groups(color)
@@ -32,7 +41,7 @@ function check_structurally_orthogonal_columns(
3241
if max_nonzeros_per_row > 1
3342
if verbose
3443
incompatible_columns = g[findall(!iszero, view(Ag, i, :))]
35-
@warn "In color $c, columns $incompatible_columns all have nonzeros in row $i"
44+
@warn "In color $c, columns $incompatible_columns all have nonzeros in row $i."
3645
end
3746
return false
3847
end
@@ -41,7 +50,7 @@ function check_structurally_orthogonal_columns(
4150
end
4251

4352
"""
44-
check_symmetrically_orthogonal_columns(
53+
symmetrically_orthogonal_columns(
4554
A::AbstractMatrix, color::AbstractVector{<:Integer};
4655
verbose=false
4756
)
@@ -60,14 +69,11 @@ A partition of the columns of a symmetrix matrix `A` is _symmetrically orthogona
6069
6170
> [_What Color Is Your Jacobian? Graph Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005)
6271
"""
63-
function check_symmetrically_orthogonal_columns(
72+
function symmetrically_orthogonal_columns(
6473
A::AbstractMatrix, color::AbstractVector{<:Integer}; verbose::Bool=false
6574
)
6675
checksquare(A)
67-
if length(color) != size(A, 2)
68-
if verbose
69-
@warn "$(length(color)) colors provided for $(size(A, 2)) columns"
70-
end
76+
if !proper_length_coloring(A, color; verbose)
7177
return false
7278
end
7379
issymmetric(A) || return false
@@ -86,12 +92,49 @@ function check_symmetrically_orthogonal_columns(
8692
gi_incompatible_columns = gi[findall(!iszero, A_gi_rowj)]
8793
@warn """
8894
For coefficient (i=$i, j=$j) with column colors (ci=$ci, cj=$cj):
89-
- in color ci=$ci, columns $gi_incompatible_columns all have nonzeros in row j=$j
90-
- in color cj=$cj, columns $gj_incompatible_columns all have nonzeros in row i=$i
95+
- In color ci=$ci, columns $gi_incompatible_columns all have nonzeros in row j=$j.
96+
- In color cj=$cj, columns $gj_incompatible_columns all have nonzeros in row i=$i.
9197
"""
9298
end
9399
return false
94100
end
95101
end
96102
return true
97103
end
104+
105+
"""
106+
directly_recoverable_columns(
107+
A::AbstractMatrix, color::AbstractVector{<:Integer}
108+
verbose=false
109+
)
110+
111+
Return `true` if coloring the columns of the symmetric matrix `A` with the vector `color` results in a column-compressed representation that preserves every unique value, thus making direct recovery possible.
112+
113+
!!! warning
114+
This function is not coded with efficiency in mind, it is designed for small-scale tests.
115+
116+
# References
117+
118+
> [_What Color Is Your Jacobian? Graph Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005)
119+
"""
120+
function directly_recoverable_columns(
121+
A::AbstractMatrix, color::AbstractVector{<:Integer}; verbose::Bool=false
122+
)
123+
if !proper_length_coloring(A, color; verbose)
124+
return false
125+
end
126+
group = color_groups(color)
127+
B = stack(group; dims=2) do g
128+
dropdims(sum(A[:, g]; dims=2); dims=2)
129+
end
130+
A_unique = Set(unique(A))
131+
B_unique = Set(unique(B))
132+
if !issubset(A_unique, B_unique)
133+
if verbose
134+
@warn "Coefficients $(sort(collect(setdiff(A_unique, B_unique)))) are not directly recoverable."
135+
return false
136+
end
137+
return false
138+
end
139+
return true
140+
end

test/check.jl

Lines changed: 68 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,122 @@
1+
using LinearAlgebra
12
using SparseMatrixColorings:
2-
check_structurally_orthogonal_columns, check_symmetrically_orthogonal_columns
3+
structurally_orthogonal_columns,
4+
symmetrically_orthogonal_columns,
5+
directly_recoverable_columns
36
using Test
47

58
@testset "Structurally orthogonal columns" begin
69
A = [
710
1 0 0
8-
0 1 0
9-
0 1 1
11+
0 2 0
12+
0 3 4
1013
]
1114

1215
# success
1316

14-
@test check_structurally_orthogonal_columns(A, [1, 2, 3])
15-
@test check_structurally_orthogonal_columns(A, [1, 2, 1])
16-
@test check_structurally_orthogonal_columns(A, [1, 1, 2])
17+
@test structurally_orthogonal_columns(A, [1, 2, 3])
18+
@test structurally_orthogonal_columns(A, [1, 2, 1])
19+
@test structurally_orthogonal_columns(A, [1, 1, 2])
20+
21+
@test directly_recoverable_columns(A, [1, 2, 3])
22+
@test directly_recoverable_columns(A, [1, 2, 1])
23+
@test directly_recoverable_columns(A, [1, 1, 2])
1724

1825
# failure
1926

20-
@test !check_structurally_orthogonal_columns(A, [1, 2])
21-
@test_logs (:warn, "2 colors provided for 3 columns") check_structurally_orthogonal_columns(
22-
A, [1, 2]; verbose=true
23-
)
27+
@test !structurally_orthogonal_columns(A, [1, 2])
28+
log = (:warn, "2 colors provided for 3 columns.")
29+
@test_logs log structurally_orthogonal_columns(A, [1, 2]; verbose=true)
2430

25-
@test !check_structurally_orthogonal_columns(A, [1, 2, 2])
26-
@test_logs (:warn, "In color 2, columns [2, 3] all have nonzeros in row 3") check_structurally_orthogonal_columns(
27-
A, [1, 2, 2]; verbose=true
28-
)
31+
@test !directly_recoverable_columns(A, [1, 2])
32+
log = (:warn, "2 colors provided for 3 columns.")
33+
@test_logs log !directly_recoverable_columns(A, [1, 2]; verbose=true)
34+
35+
@test !structurally_orthogonal_columns(A, [1, 2, 2])
36+
log = (:warn, "In color 2, columns [2, 3] all have nonzeros in row 3.")
37+
@test_logs log structurally_orthogonal_columns(A, [1, 2, 2]; verbose=true)
38+
39+
@test !directly_recoverable_columns(A, [1, 2, 2])
40+
log = (:warn, "Coefficients [3, 4] are not directly recoverable.")
2941
end
3042

3143
@testset "Structurally orthogonal rows" begin
3244
A = [
3345
1 0 0
34-
0 1 0
35-
0 1 1
46+
0 2 0
47+
0 3 4
3648
]
3749

3850
# success
3951

40-
@test check_structurally_orthogonal_columns(transpose(A), [1, 2, 3])
41-
@test check_structurally_orthogonal_columns(transpose(A), [1, 2, 1])
42-
@test check_structurally_orthogonal_columns(transpose(A), [1, 1, 2])
52+
@test structurally_orthogonal_columns(transpose(A), [1, 2, 3])
53+
@test structurally_orthogonal_columns(transpose(A), [1, 2, 1])
54+
@test structurally_orthogonal_columns(transpose(A), [1, 1, 2])
55+
56+
@test directly_recoverable_columns(transpose(A), [1, 2, 3])
57+
@test directly_recoverable_columns(transpose(A), [1, 2, 1])
58+
@test directly_recoverable_columns(transpose(A), [1, 1, 2])
4359

4460
# failure
4561

46-
@test !check_structurally_orthogonal_columns(transpose(A), [1, 2, 2, 3])
47-
@test_logs (:warn, "4 colors provided for 3 columns") check_structurally_orthogonal_columns(
48-
transpose(A), [1, 2, 2, 3]; verbose=true
49-
)
62+
@test !structurally_orthogonal_columns(transpose(A), [1, 2, 2, 3])
63+
log = (:warn, "4 colors provided for 3 columns.")
64+
@test_logs log structurally_orthogonal_columns(transpose(A), [1, 2, 2, 3]; verbose=true)
5065

51-
@test !check_structurally_orthogonal_columns(transpose(A), [1, 2, 2])
52-
@test_logs (:warn, "In color 2, columns [2, 3] all have nonzeros in row 2") !check_structurally_orthogonal_columns(
53-
transpose(A), [1, 2, 2]; verbose=true
54-
)
66+
@test !directly_recoverable_columns(transpose(A), [1, 2, 2, 3])
67+
log = (:warn, "4 colors provided for 3 columns.")
68+
@test_logs log directly_recoverable_columns(transpose(A), [1, 2, 2, 3]; verbose=true)
69+
70+
@test !structurally_orthogonal_columns(transpose(A), [1, 2, 2])
71+
log = (:warn, "In color 2, columns [2, 3] all have nonzeros in row 2.")
72+
@test_logs log !structurally_orthogonal_columns(transpose(A), [1, 2, 2]; verbose=true)
73+
74+
@test !directly_recoverable_columns(transpose(A), [1, 2, 2])
75+
log = (:warn, "Coefficients [2, 3] are not directly recoverable.")
76+
@test_logs log directly_recoverable_columns(transpose(A), [1, 2, 2]; verbose=true)
5577
end
5678

5779
@testset "Symmetrically orthogonal" begin
58-
# Fig 4.1 of "What color is your Jacobian?"
59-
60-
A = [
61-
1 1 0 0 0 0
62-
1 1 1 0 1 1
63-
0 1 1 1 0 0
64-
0 0 1 1 0 1
65-
0 1 0 0 1 0
66-
0 1 0 1 0 1
67-
]
80+
A = what_fig_41()
6881
@test issymmetric(A)
6982

7083
# success
7184

72-
@test check_symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 1])
85+
@test symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 1])
86+
87+
@test directly_recoverable_columns(A, [1, 2, 1, 3, 1, 1])
7388

7489
# failure
7590

76-
@test !check_symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1])
77-
@test_logs (:warn, "5 colors provided for 6 columns") check_symmetrically_orthogonal_columns(
91+
@test !symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1])
92+
@test_logs (:warn, "5 colors provided for 6 columns.") symmetrically_orthogonal_columns(
7893
A, [1, 2, 1, 3, 1]; verbose=true
7994
)
8095

81-
@test !check_symmetrically_orthogonal_columns(A, [1, 3, 1, 3, 1, 1])
96+
@test !symmetrically_orthogonal_columns(A, [1, 3, 1, 3, 1, 1])
8297
@test_logs (
8398
:warn,
8499
"""
85100
For coefficient (i=2, j=3) with column colors (ci=3, cj=1):
86-
- in color ci=3, columns [2, 4] all have nonzeros in row j=3
87-
- in color cj=1, columns [1, 3, 5, 6] all have nonzeros in row i=2
101+
- In color ci=3, columns [2, 4] all have nonzeros in row j=3.
102+
- In color cj=1, columns [1, 3, 5, 6] all have nonzeros in row i=2.
88103
""",
89-
) check_symmetrically_orthogonal_columns(A, [1, 3, 1, 3, 1, 1]; verbose=true)
104+
) symmetrically_orthogonal_columns(A, [1, 3, 1, 3, 1, 1]; verbose=true)
90105

91-
# Fig 1 of "Efficient computation of sparse hessians using coloring and AD"
92-
93-
A = [
94-
1 1 0 0 0 0 1 0 0 0
95-
1 1 1 0 1 0 0 0 0 0
96-
0 1 1 1 0 1 0 0 0 0
97-
0 0 1 1 0 0 0 0 0 1
98-
0 1 0 0 1 1 0 1 0 0
99-
0 0 1 0 1 1 0 0 1 0
100-
1 0 0 0 0 0 1 1 0 0
101-
0 0 0 0 1 0 1 1 1 0
102-
0 0 0 0 0 1 0 1 1 1
103-
0 0 0 1 0 0 0 0 1 1
104-
]
106+
A = efficient_fig_1()
105107
@test issymmetric(A)
106108

107109
# success
108110

109-
@test check_symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 4, 3, 5, 1, 2])
111+
@test symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 4, 3, 5, 1, 2])
110112

111113
# failure
112114

113-
@test !check_symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 4, 3, 4, 1, 2])
114-
@test !check_symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 4, 2, 5, 1, 2])
115-
@test !check_symmetrically_orthogonal_columns(A, [1, 2, 1, 4, 1, 4, 3, 5, 1, 2])
115+
@test !symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 4, 3, 4, 1, 2])
116+
@test !symmetrically_orthogonal_columns(A, [1, 2, 1, 3, 1, 4, 2, 5, 1, 2])
117+
@test !symmetrically_orthogonal_columns(A, [1, 2, 1, 4, 1, 4, 3, 5, 1, 2])
118+
119+
@test !directly_recoverable_columns(A, [1, 2, 1, 3, 1, 4, 3, 4, 1, 2])
120+
@test !directly_recoverable_columns(A, [1, 2, 1, 3, 1, 4, 2, 5, 1, 2])
121+
@test !directly_recoverable_columns(A, [1, 2, 1, 4, 1, 4, 3, 5, 1, 2])
116122
end

test/coloring_correctness.jl

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)