Skip to content

Commit aaba292

Browse files
authored
Add decompression utilities (#4)
* Add decompression utilities * Fix star coloring tests * Fix coverage
1 parent 35c22cd commit aaba292

13 files changed

+262
-69
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ version = "0.1.0"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
8+
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
89
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
910
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1011
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1112
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1213

1314
[compat]
1415
ADTypes = "1.2.1"
16+
Compat = "3,4"
1517
DocStringExtensions = "0.9"
1618
LinearAlgebra = "1"
1719
Random = "1"

docs/src/api.md

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,61 @@
22

33
```@meta
44
CollapsedDocStrings = true
5+
CurrentModule = SparseMatrixColorings
56
```
67

7-
## Public
8+
## Public, exported
89

9-
```@autodocs
10-
Modules = [SparseMatrixColorings]
11-
Private = false
10+
```@docs
11+
SparseMatrixColorings
12+
GreedyColoringAlgorithm
13+
```
14+
15+
## Public, not exported
16+
17+
### Orders
18+
19+
```@docs
20+
AbstractOrder
21+
NaturalOrder
22+
RandomOrder
23+
LargestFirst
24+
```
25+
26+
### Decompression
27+
28+
```@docs
29+
decompress_columns!
30+
decompress_columns
31+
decompress_rows!
32+
decompress_rows
1233
```
1334

1435
## Private
1536

16-
```@autodocs
17-
Modules = [SparseMatrixColorings]
18-
Public = false
37+
### Graphs
38+
39+
```@docs
40+
Graph
41+
BipartiteGraph
42+
adjacency_graph
43+
bipartite_graph
44+
neighbors
45+
vertices
46+
```
47+
48+
### Coloring
49+
50+
```@docs
51+
partial_distance2_coloring
52+
star_coloring1
53+
color_groups
54+
```
55+
56+
### Testing
57+
58+
```@docs
59+
check_structurally_orthogonal_columns
60+
check_structurally_orthogonal_rows
61+
check_symmetrically_orthogonal
1962
```

src/SparseMatrixColorings.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ $README
66
module SparseMatrixColorings
77

88
using ADTypes: ADTypes, AbstractColoringAlgorithm
9-
using DocStringExtensions
9+
using Compat: @compat
10+
using DocStringExtensions: README
1011
using LinearAlgebra: Diagonal, Transpose, checksquare, parent, transpose
1112
using Random: AbstractRNG, default_rng, randperm
1213
using SparseArrays:
@@ -15,6 +16,7 @@ using SparseArrays:
1516
dropzeros,
1617
dropzeros!,
1718
nnz,
19+
nonzeros,
1820
nzrange,
1921
rowvals,
2022
sparse,
@@ -25,6 +27,11 @@ include("order.jl")
2527
include("coloring.jl")
2628
include("adtypes.jl")
2729
include("check.jl")
30+
include("decompression.jl")
31+
32+
@compat public GreedyColoringAlgorithm
33+
@compat public NaturalOrder, RandomOrder, LargestFirst
34+
@compat public decompress_columns!, decompress_columns, decompress_rows!, decompress_rows
2835

2936
export GreedyColoringAlgorithm
3037

src/decompression.jl

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
transpose_respecting_similar(A::AbstractMatrix, ::Type{T}) where {T} = similar(A, T)
2+
3+
function transpose_respecting_similar(A::Transpose, ::Type{T}) where {T}
4+
return transpose(similar(parent(A), T))
5+
end
6+
7+
"""
8+
color_groups(colors)
9+
10+
Return `groups::Vector{Vector{Int}}` such that `i ∈ groups[c]` iff `colors[i] == c`.
11+
12+
Assumes the colors are contiguously numbered from `1` to some `cmax`.
13+
"""
14+
function color_groups(colors::AbstractVector{<:Integer})
15+
cmin, cmax = extrema(colors)
16+
@assert cmin == 1
17+
groups = [Int[] for c in 1:cmax]
18+
for (k, c) in enumerate(colors)
19+
push!(groups[c], k)
20+
end
21+
return groups
22+
end
23+
24+
## Column decompression
25+
26+
"""
27+
decompress_columns!(
28+
A::AbstractMatrix{R}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
29+
) where {R<:Real}
30+
31+
Decompress the thin matrix `C` into the fat matrix `A`.
32+
33+
Here, `C` is a compressed representation of matrix `A` obtained by summing the columns that share the same color in `colors`.
34+
"""
35+
function decompress_columns! end
36+
37+
#=
38+
function decompress_columns!(
39+
A::AbstractMatrix{R}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
40+
) where {R<:Real}
41+
A .= zero(R)
42+
@views for j in axes(A, 2)
43+
k = colors[j]
44+
rows_j = (!iszero).(A[:, j])
45+
copyto!(A[rows_j, j], C[rows_j, k])
46+
end
47+
return A
48+
end
49+
=#
50+
51+
function decompress_columns!(
52+
A::SparseMatrixCSC{R}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
53+
) where {R<:Real}
54+
Anz, Arv = nonzeros(A), rowvals(A)
55+
Anz .= zero(R)
56+
@views for j in axes(A, 2)
57+
k = colors[j]
58+
nzrange_j = nzrange(A, j)
59+
rows_j = Arv[nzrange_j]
60+
copyto!(Anz[nzrange_j], C[rows_j, k])
61+
end
62+
return A
63+
end
64+
65+
"""
66+
decompress_columns(
67+
S::AbstractMatrix{Bool}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
68+
) where {R<:Real}
69+
70+
Decompress the thin matrix `C` into a new fat matrix `A` with the same sparsity pattern as `S`.
71+
72+
Here, `C` is a compressed representation of matrix `A` obtained by summing the columns that share the same color in `colors`.
73+
"""
74+
function decompress_columns(
75+
S::AbstractMatrix{Bool}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
76+
) where {R<:Real}
77+
A = transpose_respecting_similar(S, R)
78+
return decompress_columns!(A, C, colors)
79+
end
80+
81+
## Row decompression
82+
83+
"""
84+
decompress_rows!(
85+
A::AbstractMatrix{R},
86+
C::AbstractMatrix{R}, S::AbstractMatrix{Bool},
87+
colors::AbstractVector{<:Integer}
88+
) where {R<:Real}
89+
90+
Decompress the small matrix `C` into the tall matrix `A`.
91+
92+
Here, `C` is a compressed representation of matrix `A` obtained by summing the rows that share the same color in `colors`.
93+
"""
94+
function decompress_rows! end
95+
96+
#=
97+
function decompress_rows!(
98+
A::AbstractMatrix{R}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
99+
) where {R<:Real}
100+
A .= zero(R)
101+
@views for i in axes(A, 1)
102+
k = colors[i]
103+
cols_i = (!iszero).(A[i, :])
104+
copyto!(A[i, cols_i], C[k, cols_i])
105+
end
106+
return A
107+
end
108+
=#
109+
110+
function decompress_rows!(
111+
A::Transpose{R,<:SparseMatrixCSC{R}},
112+
C::AbstractMatrix{R},
113+
colors::AbstractVector{<:Integer},
114+
) where {R<:Real}
115+
PA = parent(A)
116+
PAnz, PArv = nonzeros(PA), rowvals(PA)
117+
PAnz .= zero(R)
118+
@views for i in axes(A, 1)
119+
k = colors[i]
120+
nzrange_i = nzrange(PA, i)
121+
cols_i = PArv[nzrange_i]
122+
copyto!(PAnz[nzrange_i], C[k, cols_i])
123+
end
124+
return A
125+
end
126+
127+
"""
128+
decompress_rows(
129+
S::AbstractMatrix{Bool}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
130+
) where {R<:Real}
131+
132+
Decompress the small matrix `C` into a new tall matrix `A` with the same sparsity pattern as `S`.
133+
134+
Here, `C` is a compressed representation of matrix `A` obtained by summing the rows that share the same color in `colors`.
135+
"""
136+
function decompress_rows(
137+
S::AbstractMatrix{Bool}, C::AbstractMatrix{R}, colors::AbstractVector{<:Integer}
138+
) where {R<:Real}
139+
A = transpose_respecting_similar(S, R)
140+
return decompress_rows!(A, C, colors)
141+
end

src/graph.jl

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -110,20 +110,3 @@ function bipartite_graph(J::SparseMatrixCSC)
110110
end
111111

112112
bipartite_graph(J::AbstractMatrix) = bipartite_graph(sparse(J))
113-
114-
"""
115-
column_intersection_graph(J::AbstractMatrix)
116-
117-
Return a [`Graph`](@ref) representing the column intersections of a non-symmetric matrix (typically a Jacobian matrix).
118-
119-
The column intersection graph of a matrix `A ∈ ℝ^{m × n}` is `Gc(A) = (V, E)` where
120-
121-
- `V = 1:n` is the set of columns `j`
122-
- `(j1, j2) ∈ E` whenever `A[:, j1] ∩ A[:, j2] ≠ ∅`
123-
"""
124-
function column_intersection_graph(J::SparseMatrixCSC)
125-
A = transpose(J) * J
126-
return adjacency_graph(A - Diagonal(A))
127-
end
128-
129-
column_intersection_graph(J::AbstractMatrix) = column_intersection_graph(sparse(J))

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
33
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
44
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
55
Chairmarks = "0ca39b1e-fe0b-4e98-acfc-b1656634c4de"
6+
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
67
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
78
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
89
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"

test/adtypes.jl renamed to test/coloring_correctness.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ using SparseMatrixColorings:
88
check_symmetrically_orthogonal
99
using Test
1010

11-
alg = GreedyColoringAlgorithm()
11+
algo = GreedyColoringAlgorithm()
12+
13+
@test startswith(string(algo), "GreedyColoringAlgorithm(")
1214

1315
@testset "Column coloring" begin
1416
for A in (sprand(Bool, 100, 200, 0.05), sprand(Bool, 200, 100, 0.05))
15-
column_colors = column_coloring(A, alg)
17+
column_colors = column_coloring(A, algo)
1618
@test check_structurally_orthogonal_columns(A, column_colors)
1719
@test minimum(column_colors) == 1
1820
@test maximum(column_colors) < size(A, 2) ÷ 2
@@ -21,7 +23,7 @@ end
2123

2224
@testset "Row coloring" begin
2325
for A in (sprand(Bool, 100, 200, 0.05), sprand(Bool, 200, 100, 0.05))
24-
row_colors = row_coloring(A, alg)
26+
row_colors = row_coloring(A, algo)
2527
@test check_structurally_orthogonal_rows(A, row_colors)
2628
@test minimum(row_colors) == 1
2729
@test maximum(row_colors) < size(A, 1) ÷ 2
@@ -30,7 +32,7 @@ end
3032

3133
@testset "Symmetric coloring" begin
3234
S = sparse(Symmetric(sprand(Bool, 100, 100, 0.05)))
33-
symmetric_colors = symmetric_coloring(S, alg)
35+
symmetric_colors = symmetric_coloring(S, algo)
3436
@test check_symmetrically_orthogonal(S, symmetric_colors)
3537
@test minimum(symmetric_colors) == 1
3638
@test maximum(symmetric_colors) < size(S, 2) ÷ 2
File renamed without changes.

test/decompression_correctness.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using ADTypes: column_coloring, row_coloring, symmetric_coloring
2+
using Compat
3+
using SparseArrays
4+
using SparseMatrixColorings: color_groups, decompress_columns, decompress_rows
5+
using StableRNGs
6+
using Test
7+
8+
rng = StableRNG(63)
9+
10+
algo = GreedyColoringAlgorithm()
11+
12+
m, n = 10, 20
13+
A = sprand(rng, Bool, m, n, 0.3)
14+
At = transpose(A)
15+
S = map(!iszero, A)
16+
St = transpose(S)
17+
18+
@testset "Column decompression" begin
19+
colors = column_coloring(A, algo)
20+
groups = color_groups(colors)
21+
@test length(groups[1]) > 1
22+
C = stack(groups) do group
23+
dropdims(sum(A[:, group]; dims=2); dims=2)
24+
end
25+
A_new = decompress_columns(S, C, colors)
26+
@test A_new == A
27+
end
28+
29+
@testset "Row decompression" begin
30+
colors = row_coloring(At, algo)
31+
groups = color_groups(colors)
32+
@test length(groups[1]) > 1
33+
Ct = stack(groups; dims=1) do group
34+
dropdims(sum(At[group, :]; dims=1); dims=1)
35+
end
36+
At_new = decompress_rows(St, Ct, colors)
37+
@test At_new == At
38+
end

test/reference/what_table_41_42.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
row,modified,group,name,V,E,,δ,K_d2,K_star1,K_star2
1+
row,modified,group,name,V,E,Δ,δ,K_d2,K_star1,K_star2
22
1,false,,mrng1,257000,505048,4,2,12,8,10
33
2,false,,mrng2,1017253,2015714,4,2,12,9,10
4-
3,false,DIMACS10,598a,110971,741934,26,5 13,38,27,32
4+
3,false,DIMACS10,598a,110971,741934,26,5,38,27,32
55
4,false,DIMACS10,144,144649,1074393,26,4,41,28,35
66
5,false,DIMACS10,m14b,214765,1679018,40,4,42,29,34
77
6,false,DIMACS10,auto,448695,3314611,37,4,42,29,36

test/runtests.jl

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,23 @@ using Test
3636
end
3737
end
3838
@testset verbose = true "Correctness" begin
39-
@testset "ADTypes" begin
40-
include("adtypes.jl")
39+
@testset "Coloring" begin
40+
include("coloring_correctness.jl")
4141
end
42-
@testset "SuiteSparse" begin
43-
include("suitesparse.jl")
42+
@testset "Decompression" begin
43+
include("decompression_correctness.jl")
4444
end
4545
end
4646
@testset "Performance" begin
4747
if VERSION >= v"1.10"
48-
include("performance.jl")
48+
@testset "Coloring" begin
49+
include("coloring_performance.jl")
50+
end
51+
end
52+
end
53+
@testset "Comparison" begin
54+
@testset "SuiteSparse" begin
55+
include("suitesparse.jl")
4956
end
5057
end
5158
end

0 commit comments

Comments
 (0)