API reference
The docstrings on this page define the public API of the package.
SparseMatrixColorings.SparseMatrixColorings
— ModuleSparseMatrixColorings
SparseMatrixColorings.jl
Coloring algorithms for sparse Jacobian and Hessian matrices.
Getting started
To install this package, run the following in a Julia Pkg REPL:
pkg> add SparseMatrixColorings
Background
The algorithms implemented in this package are taken from the following articles:
- What Color Is Your Jacobian? Graph Coloring for Computing Derivatives, Gebremedhin et al. (2005)
- New Acyclic and Star Coloring Algorithms with Application to Computing Hessians, Gebremedhin et al. (2007)
- Efficient Computation of Sparse Hessians Using Coloring and Automatic Differentiation, Gebremedhin et al. (2009)
- ColPack: Software for graph coloring and related problems in scientific computing, Gebremedhin et al. (2013)
Some parts of the articles (like definitions) are thus copied verbatim in the documentation.
Alternatives
- ColPack.jl: a Julia interface to the C++ library ColPack
- SparseDiffTools.jl: contains Julia implementations of some coloring algorithms
Citing
Please cite this software using the Zenodo DOI of the version you used. The link https://zenodo.org/doi/10.5281/zenodo.11314275 resolves to the latest version.
Exports
AbstractColoringResult
ColoringProblem
ConstantColoringAlgorithm
DynamicDegreeBasedOrder
DynamicLargestFirst
GreedyColoringAlgorithm
IncidenceDegree
LargestFirst
NaturalOrder
RandomOrder
SmallestLast
coloring
column_colors
column_groups
compress
decompress
decompress!
decompress_single_color!
ncolors
row_colors
row_groups
sparsity_pattern
Main function
SparseMatrixColorings.coloring
— Functioncoloring(
S::AbstractMatrix,
problem::ColoringProblem,
algo::GreedyColoringAlgorithm;
[decompression_eltype=Float64, symmetric_pattern=false]
)
Solve a ColoringProblem
on the matrix S
with a GreedyColoringAlgorithm
and return an AbstractColoringResult
.
The result can be used to compress
and decompress
a matrix A
with the same sparsity pattern as S
. If eltype(A) == decompression_eltype
, decompression might be faster.
For a :nonsymmetric
problem (and only then), setting symmetric_pattern=true
indicates that the pattern of nonzeros is symmetric. This condition is weaker than the symmetry of actual values, so it can happen for some Jacobians. Specifying it allows faster construction of the bipartite graph.
Example
julia> using SparseMatrixColorings, SparseArrays
julia> S = sparse([
0 0 1 1 0 1
1 0 0 0 1 0
0 1 0 0 1 0
0 1 1 0 0 0
]);
julia> problem = ColoringProblem(; structure=:nonsymmetric, partition=:column);
julia> algo = GreedyColoringAlgorithm(; decompression=:direct);
julia> result = coloring(S, problem, algo);
julia> column_colors(result)
6-element Vector{Int64}:
1
1
2
1
2
3
julia> collect.(column_groups(result))
3-element Vector{Vector{Int64}}:
[1, 2, 4]
[3, 5]
[6]
See also
SparseMatrixColorings.ColoringProblem
— TypeColoringProblem{structure,partition}
Selector type for the coloring problem to solve, enabling multiple dispatch.
It is passed as an argument to the main function coloring
.
Constructors
ColoringProblem{structure,partition}()
ColoringProblem(; structure=:nonsymmetric, partition=:column)
structure::Symbol
: either:nonsymmetric
or:symmetric
partition::Symbol
: either:column
,:row
or:bidirectional
The second constructor (based on keyword arguments) is type-unstable.
Link to automatic differentiation
Matrix coloring is often used in automatic differentiation, and here is the translation guide:
matrix | mode | structure | partition | implemented |
---|---|---|---|---|
Jacobian | forward | :nonsymmetric | :column | yes |
Jacobian | reverse | :nonsymmetric | :row | yes |
Jacobian | mixed | :nonsymmetric | :bidirectional | yes |
Hessian | - | :symmetric | :column | yes |
Hessian | - | :symmetric | :row | no |
SparseMatrixColorings.GreedyColoringAlgorithm
— TypeGreedyColoringAlgorithm{decompression} <: ADTypes.AbstractColoringAlgorithm
Greedy coloring algorithm for sparse matrices which colors columns or rows one after the other, following a configurable order.
It is passed as an argument to the main function coloring
.
Constructors
GreedyColoringAlgorithm{decompression}(order=NaturalOrder())
GreedyColoringAlgorithm(order=NaturalOrder(); decompression=:direct)
order::AbstractOrder
: the order in which the columns or rows are colored, which can impact the number of colors.decompression::Symbol
: either:direct
or:substitution
. Usually:substitution
leads to fewer colors, at the cost of a more expensive coloring (and decompression). When:substitution
is not applicable, it falls back on:direct
decompression.
The second constructor (based on keyword arguments) is type-unstable.
ADTypes coloring interface
GreedyColoringAlgorithm
is a subtype of ADTypes.AbstractColoringAlgorithm
, which means the following methods are also applicable:
See their respective docstrings for details.
See also
SparseMatrixColorings.ConstantColoringAlgorithm
— TypeConstantColoringAlgorithm{partition} <: ADTypes.AbstractColoringAlgorithm
Coloring algorithm which always returns the same precomputed vector of colors. Useful when the optimal coloring of a matrix can be determined a priori due to its specific structure (e.g. banded).
It is passed as an argument to the main function coloring
, but will only work if the associated problem
has :nonsymmetric
structure. Indeed, for symmetric coloring problems, we need more than just the vector of colors to allow fast decompression.
Constructors
ConstantColoringAlgorithm{partition}(matrix_template, color)
ConstantColoringAlgorithm(matrix_template, color; partition=:column)
partition::Symbol
: either:row
or:column
.matrix_template::AbstractMatrix
: matrix for which the vector of colors was precomputed (the algorithm will only accept matrices of the exact same size).color::Vector{Int}
: vector of integer colors, one for each row or column (depending onpartition
).
The second constructor (based on keyword arguments) is type-unstable.
We do not necessarily verify consistency between the matrix template and the vector of colors, this is the responsibility of the user.
Example
julia> using SparseMatrixColorings, LinearAlgebra
julia> matrix_template = Diagonal(ones(Bool, 5))
5×5 Diagonal{Bool, Vector{Bool}}:
1 ⋅ ⋅ ⋅ ⋅
⋅ 1 ⋅ ⋅ ⋅
⋅ ⋅ 1 ⋅ ⋅
⋅ ⋅ ⋅ 1 ⋅
⋅ ⋅ ⋅ ⋅ 1
julia> color = ones(Int, 5) # coloring a Diagonal is trivial
5-element Vector{Int64}:
1
1
1
1
1
julia> problem = ColoringProblem(; structure=:nonsymmetric, partition=:column);
julia> algo = ConstantColoringAlgorithm(matrix_template, color; partition=:column);
julia> result = coloring(similar(matrix_template), problem, algo);
julia> column_colors(result)
5-element Vector{Int64}:
1
1
1
1
1
ADTypes coloring interface
ConstantColoringAlgorithm
is a subtype of ADTypes.AbstractColoringAlgorithm
, which means the following methods are also applicable (although they will error if the kind of coloring demanded not consistent):
Result analysis
SparseMatrixColorings.AbstractColoringResult
— TypeAbstractColoringResult{structure,partition,decompression}
Abstract type for the result of a coloring algorithm.
It is the supertype of the object returned by the main function coloring
.
Type parameters
Combination between the type parameters of ColoringProblem
and GreedyColoringAlgorithm
:
structure::Symbol
: either:nonsymmetric
or:symmetric
partition::Symbol
: either:column
,:row
or:bidirectional
decompression::Symbol
: either:direct
or:substitution
Applicable methods
column_colors
andcolumn_groups
(for a:column
or:bidirectional
partition)row_colors
androw_groups
(for a:row
or:bidirectional
partition)sparsity_pattern
compress
,decompress
,decompress!
,decompress_single_color!
Unlike the methods above, the concrete subtypes of AbstractColoringResult
are not part of the public API and may change without notice.
SparseMatrixColorings.column_colors
— Functioncolumn_colors(result::AbstractColoringResult)
Return a vector color
of integer colors, one for each column of the colored matrix.
SparseMatrixColorings.row_colors
— Functionrow_colors(result::AbstractColoringResult)
Return a vector color
of integer colors, one for each row of the colored matrix.
SparseMatrixColorings.ncolors
— Functionncolors(result::AbstractColoringResult)
Return the number of different colors used to color the matrix.
For bidirectional partitions, this number is the sum of the number of row colors and the number of column colors.
SparseMatrixColorings.column_groups
— Functioncolumn_groups(result::AbstractColoringResult)
Return a vector group
such that for every color c
, group[c]
contains the indices of all columns that are colored with c
.
SparseMatrixColorings.row_groups
— Functionrow_groups(result::AbstractColoringResult)
Return a vector group
such that for every color c
, group[c]
contains the indices of all rows that are colored with c
.
SparseMatrixColorings.sparsity_pattern
— Functionsparsity_pattern(result::AbstractColoringResult)
Return the matrix that was initially passed to coloring
, without any modifications.
This matrix is not necessarily a SparseMatrixCSC
, nor does it necessarily have Bool
entries.
Decompression
SparseMatrixColorings.compress
— Functioncompress(A, result::AbstractColoringResult)
Compress A
given a coloring result
of the sparsity pattern of A
.
- If
result
comes from a:column
(resp.:row
) partition, the output is a single matrixB
compressed by column (resp. by row). - If
result
comes from a:bidirectional
partition, the output is a tuple of matrices(Br, Bc)
, whereBr
is compressed by row andBc
by column.
Compression means summing either the columns or the rows of A
which share the same color. It is undone by calling decompress
or decompress!
.
Example
julia> using SparseMatrixColorings, SparseArrays
julia> A = sparse([
0 0 4 6 0 9
1 0 0 0 7 0
0 2 0 0 8 0
0 3 5 0 0 0
]);
julia> result = coloring(A, ColoringProblem(), GreedyColoringAlgorithm());
julia> collect.(column_groups(result))
3-element Vector{Vector{Int64}}:
[1, 2, 4]
[3, 5]
[6]
julia> B = compress(A, result)
4×3 Matrix{Int64}:
6 4 9
1 7 0
2 8 0
3 5 0
See also
SparseMatrixColorings.decompress
— Functiondecompress(B::AbstractMatrix, result::AbstractColoringResult{_,:column/:row})
decompress(Br::AbstractMatrix, Bc::AbstractMatrix, result::AbstractColoringResult{_,:bidirectional})
Decompress B
(or the tuple (Br,Bc)
) into a new matrix A
, given a coloring result
of the sparsity pattern of A
. The in-place alternative is decompress!
.
Compression means summing either the columns or the rows of A
which share the same color. It is done by calling compress
.
Example
julia> using SparseMatrixColorings, SparseArrays
julia> A = sparse([
0 0 4 6 0 9
1 0 0 0 7 0
0 2 0 0 8 0
0 3 5 0 0 0
]);
julia> result = coloring(A, ColoringProblem(), GreedyColoringAlgorithm());
julia> collect.(column_groups(result))
3-element Vector{Vector{Int64}}:
[1, 2, 4]
[3, 5]
[6]
julia> B = compress(A, result)
4×3 Matrix{Int64}:
6 4 9
1 7 0
2 8 0
3 5 0
julia> decompress(B, result)
4×6 SparseMatrixCSC{Int64, Int64} with 9 stored entries:
⋅ ⋅ 4 6 ⋅ 9
1 ⋅ ⋅ ⋅ 7 ⋅
⋅ 2 ⋅ ⋅ 8 ⋅
⋅ 3 5 ⋅ ⋅ ⋅
julia> decompress(B, result) == A
true
See also
SparseMatrixColorings.decompress!
— Functiondecompress!(
A::AbstractMatrix, B::AbstractMatrix,
result::AbstractColoringResult{_,:column/:row}, [uplo=:F]
)
decompress!(
A::AbstractMatrix, Br::AbstractMatrix, Bc::AbstractMatrix
result::AbstractColoringResult{_,:bidirectional}
)
Decompress B
(or the tuple (Br,Bc)
) in-place into A
, given a coloring result
of the sparsity pattern of A
. The out-of-place alternative is decompress
.
In-place decompression is faster when A isa SparseMatrixCSC
.
Compression means summing either the columns or the rows of A
which share the same color. It is done by calling compress
.
For :symmetric
coloring results (and for those only), an optional positional argument uplo in (:U, :L, :F)
can be passed to specify which part of the matrix A
should be updated: the Upper triangle, the Lower triangle, or the Full matrix. When A isa SparseMatrixCSC
, using the uplo
argument requires a target matrix which only stores the relevant triangle(s).
Example
julia> using SparseMatrixColorings, SparseArrays
julia> A = sparse([
0 0 4 6 0 9
1 0 0 0 7 0
0 2 0 0 8 0
0 3 5 0 0 0
]);
julia> result = coloring(A, ColoringProblem(), GreedyColoringAlgorithm());
julia> collect.(column_groups(result))
3-element Vector{Vector{Int64}}:
[1, 2, 4]
[3, 5]
[6]
julia> B = compress(A, result)
4×3 Matrix{Int64}:
6 4 9
1 7 0
2 8 0
3 5 0
julia> A2 = similar(A);
julia> decompress!(A2, B, result)
4×6 SparseMatrixCSC{Int64, Int64} with 9 stored entries:
⋅ ⋅ 4 6 ⋅ 9
1 ⋅ ⋅ ⋅ 7 ⋅
⋅ 2 ⋅ ⋅ 8 ⋅
⋅ 3 5 ⋅ ⋅ ⋅
julia> A2 == A
true
See also
SparseMatrixColorings.decompress_single_color!
— Functiondecompress_single_color!(
A::AbstractMatrix, b::AbstractVector, c::Integer,
result::AbstractColoringResult, [uplo=:F]
)
Decompress the vector b
corresponding to color c
in-place into A
, given a :direct
coloring result
of the sparsity pattern of A
(it will not work with a :substitution
coloring).
- If
result
comes from a:nonsymmetric
structure with:column
partition, this will update the columns ofA
that share colorc
(whose sum makes upb
). - If
result
comes from a:nonsymmetric
structure with:row
partition, this will update the rows ofA
that share colorc
(whose sum makes upb
). - If
result
comes from a:symmetric
structure with:column
partition, this will update the coefficients ofA
whose value is deduced from colorc
.
This function will only update some coefficients of A
, without resetting the rest to zero.
For :symmetric
coloring results (and for those only), an optional positional argument uplo in (:U, :L, :F)
can be passed to specify which part of the matrix A
should be updated: the Upper triangle, the Lower triangle, or the Full matrix. When A isa SparseMatrixCSC
, using the uplo
argument requires a target matrix which only stores the relevant triangle(s).
Example
julia> using SparseMatrixColorings, SparseArrays
julia> A = sparse([
0 0 4 6 0 9
1 0 0 0 7 0
0 2 0 0 8 0
0 3 5 0 0 0
]);
julia> result = coloring(A, ColoringProblem(), GreedyColoringAlgorithm());
julia> collect.(column_groups(result))
3-element Vector{Vector{Int64}}:
[1, 2, 4]
[3, 5]
[6]
julia> B = compress(A, result)
4×3 Matrix{Int64}:
6 4 9
1 7 0
2 8 0
3 5 0
julia> A2 = similar(A); A2 .= 0;
julia> decompress_single_color!(A2, B[:, 2], 2, result)
4×6 SparseMatrixCSC{Int64, Int64} with 9 stored entries:
⋅ ⋅ 4 0 ⋅ 0
0 ⋅ ⋅ ⋅ 7 ⋅
⋅ 0 ⋅ ⋅ 8 ⋅
⋅ 0 5 ⋅ ⋅ ⋅
julia> A2[:, [3, 5]] == A[:, [3, 5]]
true
See also
Orders
SparseMatrixColorings.AbstractOrder
— TypeAbstractOrder
Abstract supertype for the vertex order used inside GreedyColoringAlgorithm
.
In this algorithm, the rows and columns of a matrix form a graph, and the vertices are colored one after the other in a greedy fashion. Depending on how the vertices are ordered, the number of colors necessary may vary.
Options
NaturalOrder
RandomOrder
LargestFirst
IncidenceDegree
(experimental)SmallestLast
(experimental)DynamicLargestFirst
(experimental)
SparseMatrixColorings.NaturalOrder
— TypeNaturalOrder()
Instance of AbstractOrder
which sorts vertices using their index in the provided graph.
SparseMatrixColorings.RandomOrder
— TypeRandomOrder(rng=default_rng())
Instance of AbstractOrder
which sorts vertices using a random permutation.
SparseMatrixColorings.LargestFirst
— TypeLargestFirst()
Instance of AbstractOrder
which sorts vertices using their degree in the provided graph: the largest degree comes first.
SparseMatrixColorings.SmallestLast
— TypeSmallestLast()
Instance of AbstractOrder
which sorts vertices from highest to lowest using the dynamic back degree.
This order is still experimental and needs more tests, correctness is not yet guaranteed.
See also
SparseMatrixColorings.IncidenceDegree
— TypeIncidenceDegree()
Instance of AbstractOrder
which sorts vertices from lowest to highest using the dynamic back degree.
This order is still experimental and needs more tests, correctness is not yet guaranteed.
See also
SparseMatrixColorings.DynamicLargestFirst
— TypeDynamicLargestFirst()
Instance of AbstractOrder
which sorts vertices from lowest to highest using the dynamic forward degree.
This order is still experimental and needs more tests, correctness is not yet guaranteed.
See also
SparseMatrixColorings.DynamicDegreeBasedOrder
— TypeDynamicDegreeBasedOrder{degtype,direction}
Instance of AbstractOrder
which sorts vertices using a dynamically computed degree.
This order is still experimental and needs more tests, correctness is not yet guaranteed.
Type parameters
degtype::Symbol
: can be:forward
(for the forward degree) or:back
(for the back degree)direction::Symbol
: can be:low2high
(if the order is defined from lowest to highest, i.e.1
ton
) or:high2low
(if the order is defined from highest to lowest, i.e.n
to1
)
Concrete variants
References
- ColPack: Software for graph coloring and related problems in scientific computing, Gebremedhin et al. (2013), Section 5