Skip to content

Commit 923f8a8

Browse files
Merge pull request #38 from JuliaDiffEq/vectorized
Vectorized decompression
2 parents bf44735 + 70cb8b7 commit 923f8a8

File tree

6 files changed

+48
-79
lines changed

6 files changed

+48
-79
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1313
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
1414
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1515
VertexSafeGraphs = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f"
16+
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
1617

1718
[compat]
19+
ArrayInterface = "1.1"
1820
julia = "1"
1921

2022
[extras]

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ gmres!(res,J,v)
9393

9494
### Matrix Coloring
9595

96+
This library extends the common `ArrayInterface.matrix_colors` function to allow
97+
for coloring sparse matrices using graphical techniques.
98+
9699
Matrix coloring allows you to reduce the number of times finite differencing
97100
requires an `f` call to `maximum(colors)+1`, or reduces automatic differentiation
98101
to using `maximum(colors)` partials. Since normally these values are `length(x)`,
@@ -101,7 +104,8 @@ this can be significant savings.
101104
The API for computing the color vector is:
102105

103106
```julia
104-
matrix_colors(A::AbstractMatrix,alg::ColoringAlgorithm = GreedyD1Color(); partition_by_rows::Bool = false)
107+
matrix_colors(A::AbstractMatrix,alg::ColoringAlgorithm = GreedyD1Color();
108+
partition_by_rows::Bool = false)
105109
```
106110

107111
The first argument is the abstract matrix which represents the sparsity pattern

src/SparseDiffTools.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ using Requires
99
using VertexSafeGraphs
1010

1111
using LinearAlgebra
12-
using SparseArrays
12+
using SparseArrays, ArrayInterface
1313

1414
using BlockBandedMatrices: blocksize, nblocks
1515
using ForwardDiff: Dual, jacobian, partials, DEFAULT_CHUNK_THRESHOLD
1616

17+
using ArrayInterface: matrix_colors
1718

1819
export contract_color,
1920
greedy_d1,

src/coloring/high_level.jl

Lines changed: 7 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
abstract type ColoringAlgorithm end
2-
struct GreedyD1Color <: ColoringAlgorithm end
3-
struct BacktrackingColor <: ColoringAlgorithm end
4-
struct ContractionColor <: ColoringAlgorithm end
5-
struct GreedyStar1Color <: ColoringAlgorithm end
6-
struct GreedyStar2Color <: ColoringAlgorithm end
1+
abstract type SparseDiffToolsColoringAlgorithm <: ArrayInterface.ColoringAlgorithm end
2+
struct GreedyD1Color <: SparseDiffToolsColoringAlgorithm end
3+
struct BacktrackingColor <: SparseDiffToolsColoringAlgorithm end
4+
struct ContractionColor <: SparseDiffToolsColoringAlgorithm end
5+
struct GreedyStar1Color <: SparseDiffToolsColoringAlgorithm end
6+
struct GreedyStar2Color <: SparseDiffToolsColoringAlgorithm end
77

88
"""
99
matrix_colors(A,alg::ColoringAlgorithm = GreedyD1Color())
@@ -13,70 +13,8 @@ struct GreedyStar2Color <: ColoringAlgorithm end
1313
The coloring defaults to a greedy distance-1 coloring.
1414
1515
"""
16-
function matrix_colors(A::AbstractMatrix,alg::ColoringAlgorithm = GreedyD1Color(); partition_by_rows::Bool = false)
16+
function ArrayInterface.matrix_colors(A::AbstractMatrix,alg::SparseDiffToolsColoringAlgorithm = GreedyD1Color(); partition_by_rows::Bool = false)
1717
_A = A isa SparseMatrixCSC ? A : sparse(A) # Avoid the copy
1818
A_graph = matrix2graph(_A, partition_by_rows)
1919
color_graph(A_graph,alg)
2020
end
21-
22-
"""
23-
matrix_colors(A::Union{Array,UpperTriangular,LowerTriangular})
24-
25-
The color vector for dense matrix and triangular matrix is simply
26-
`[1,2,3,...,size(A,2)]`
27-
"""
28-
function matrix_colors(A::Union{Array,UpperTriangular,LowerTriangular})
29-
eachindex(1:size(A,2)) # Vector size matches number of rows
30-
end
31-
32-
function _cycle(repetend,len)
33-
repeat(repetend,div(len,length(repetend))+1)[1:len]
34-
end
35-
36-
function matrix_colors(A::Diagonal)
37-
fill(1,size(A,2))
38-
end
39-
40-
function matrix_colors(A::Bidiagonal)
41-
_cycle(1:2,size(A,2))
42-
end
43-
44-
function matrix_colors(A::Union{Tridiagonal,SymTridiagonal})
45-
_cycle(1:3,size(A,2))
46-
end
47-
48-
function matrix_colors(A::BandedMatrix)
49-
u,l=bandwidths(A)
50-
width=u+l+1
51-
_cycle(1:width,size(A,2))
52-
end
53-
54-
function matrix_colors(A::BlockBandedMatrix)
55-
l,u=blockbandwidths(A)
56-
blockwidth=l+u+1
57-
nblock=nblocks(A,2)
58-
cols=[blocksize(A,(1,i))[2] for i in 1:nblock]
59-
blockcolors=_cycle(1:blockwidth,nblock)
60-
#the reserved number of colors of a block is the maximum length of columns of blocks with the same block color
61-
ncolors=[maximum(cols[i:blockwidth:nblock]) for i in 1:blockwidth]
62-
endinds=cumsum(ncolors)
63-
startinds=[endinds[i]-ncolors[i]+1 for i in 1:blockwidth]
64-
colors=[(startinds[blockcolors[i]]:endinds[blockcolors[i]])[1:cols[i]] for i in 1:nblock]
65-
vcat(colors...)
66-
end
67-
68-
function matrix_colors(A::BandedBlockBandedMatrix)
69-
l,u=blockbandwidths(A)
70-
lambda,mu=subblockbandwidths(A)
71-
blockwidth=l+u+1
72-
subblockwidth=lambda+mu+1
73-
nblock=nblocks(A,2)
74-
cols=[blocksize(A,(1,i))[2] for i in 1:nblock]
75-
blockcolors=_cycle(1:blockwidth,nblock)
76-
#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
77-
ncolors=[min(subblockwidth,maximum(cols[i:blockwidth:nblock])) for i in 1:min(blockwidth,nblock)]
78-
endinds=cumsum(ncolors)
79-
startinds=[endinds[i]-ncolors[i]+1 for i in 1:min(blockwidth,nblock)]
80-
colors=[_cycle(startinds[blockcolors[i]]:endinds[blockcolors[i]],cols[i]) for i in 1:nblock]
81-
vcat(colors...)
82-
end

src/differentiation/compute_jacobian_ad.jl

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ getsize(N::Integer) = N
2121
function ForwardColorJacCache(f,x,_chunksize = nothing;
2222
dx = nothing,
2323
color=1:length(x),
24-
sparsity::Union{SparseMatrixCSC,Nothing}=nothing)
24+
sparsity::Union{AbstractArray,Nothing}=nothing)
2525

2626
if _chunksize === nothing
2727
chunksize = default_chunk_size(maximum(color))
@@ -81,7 +81,7 @@ function forwarddiff_color_jacobian!(J::AbstractMatrix{<:Number},
8181
x::AbstractArray{<:Number};
8282
dx = nothing,
8383
color = eachindex(x),
84-
sparsity = J isa SparseMatrixCSC ? J : nothing)
84+
sparsity = ArrayInterface.has_sparsestruct(J) ? J : nothing)
8585
forwarddiff_color_jacobian!(J,f,x,ForwardColorJacCache(f,x,dx=dx,color=color,sparsity=sparsity))
8686
end
8787

@@ -98,18 +98,37 @@ function forwarddiff_color_jacobian!(J::AbstractMatrix{<:Number},
9898
sparsity = jac_cache.sparsity
9999
color_i = 1
100100
chunksize = length(first(first(jac_cache.p)))
101+
fill!(J, zero(eltype(J)))
101102

102-
for i in 1:length(p)
103+
for i in eachindex(p)
103104
partial_i = p[i]
104105
t .= Dual{typeof(f)}.(x, partial_i)
105106
f(fx,t)
106-
if sparsity isa SparseMatrixCSC
107-
rows_index, cols_index, val = findnz(sparsity)
107+
if ArrayInterface.has_sparsestruct(sparsity)
108+
rows_index, cols_index = ArrayInterface.findstructralnz(sparsity)
108109
for j in 1:chunksize
109110
dx .= partials.(fx, j)
110-
for k in 1:length(cols_index)
111-
if color[cols_index[k]] == color_i
112-
J[rows_index[k], cols_index[k]] = dx[rows_index[k]]
111+
if ArrayInterface.fast_scalar_indexing(dx)
112+
for k in 1:length(cols_index)
113+
if color[cols_index[k]] == color_i
114+
if J isa SparseMatrixCSC
115+
J.nzval[k] = dx[rows_index[k]]
116+
else
117+
J[rows_index[k],cols_index[k]] = dx[rows_index[k]]
118+
end
119+
end
120+
end
121+
else
122+
#=
123+
J.nzval[rows_index] .+= (color[cols_index] .== color_i) .* dx[rows_index]
124+
or
125+
J[rows_index, cols_index] .+= (color[cols_index] .== color_i) .* dx[rows_index]
126+
+= means requires a zero'd out start
127+
=#
128+
if J isa SparseMatrixCSC
129+
@. setindex!((J.nzval,),getindex((J.nzval,),rows_index) + (getindex((color,),cols_index) == color_i) * getindex((dx,),rows_index),rows_index)
130+
else
131+
@. setindex!((J,),getindex((J,),rows_index, cols_index) + (getindex((color,),cols_index) == color_i) * getindex((dx,),rows_index),rows_index, cols_index)
113132
end
114133
end
115134
color_i += 1

test/test_ad.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using SparseDiffTools
22
using ForwardDiff: Dual, jacobian
33
using SparseArrays, Test
4+
using LinearAlgebra
45

56
fcalls = 0
67
function f(dx,x)
@@ -56,3 +57,7 @@ jac_cache = ForwardColorJacCache(f,x,color = repeat(1:3,10), sparsity = _J1)
5657
forwarddiff_color_jacobian!(_denseJ1, f, x, jac_cache)
5758
@test _denseJ1 J
5859
@test fcalls == 1
60+
61+
_Jt = similar(Tridiagonal(J))
62+
forwarddiff_color_jacobian!(_Jt, f, x, color = repeat(1:3,10), sparsity = _Jt)
63+
@test _Jt J

0 commit comments

Comments
 (0)