diff --git a/docs/src/index.md b/docs/src/index.md index 2100fb2..f2c44e6 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -87,6 +87,7 @@ ADTypes.AbstractColoringAlgorithm ADTypes.column_coloring ADTypes.row_coloring ADTypes.symmetric_coloring +ADTypes.bicoloring ADTypes.NoColoringAlgorithm ``` diff --git a/src/ADTypes.jl b/src/ADTypes.jl index 0a1f66d..9558eb2 100644 --- a/src/ADTypes.jl +++ b/src/ADTypes.jl @@ -68,7 +68,7 @@ export jacobian_sparsity, hessian_sparsity # Matrix coloring export AbstractColoringAlgorithm -export column_coloring, row_coloring, symmetric_coloring +export column_coloring, row_coloring, symmetric_coloring, bicoloring @public coloring_algorithm @public NoColoringAlgorithm diff --git a/src/sparse.jl b/src/sparse.jl index 953c334..80beb63 100644 --- a/src/sparse.jl +++ b/src/sparse.jl @@ -115,6 +115,7 @@ Abstract supertype for Jacobian/Hessian coloring algorithms. - [`column_coloring`](@ref) - [`row_coloring`](@ref) - [`symmetric_coloring`](@ref) + - [`bicoloring`](@ref) # Note @@ -154,6 +155,23 @@ The result is a coloring vector `c` of length `size(M, 1) == size(M, 2)` such th """ function symmetric_coloring end +""" + bicoloring(M::AbstractMatrix, ca::ColoringAlgorithm)::Tuple{AbstractVector{<:Integer},AbstractVector{<:Integer}} + +Use algorithm `ca` to construct a structurally orthogonal partition of both the rows and columns of the matrix `M`, ensuring no two non-zero entries in the same row or column share the same color. + +The result is a tuple of coloring vectors `(cr, cc)` of lengths `size(M, 1)` and `size(M, 2)`, respectively. +The vector `cr` provides a color assignment for each row, and `cc` provides a color assignment for each column. +For each non-zero entry `M[i, j]` in `M`, at least one of the following conditions holds: + + - row `i` is the only row with color `cr[i]` that has a non-zero entry in column `j`; + - column `j` is the only column with color `cc[j]` that has a non-zero entry in row `i`. + +A neutral color `0` may be assigned to rows or columns, indicating that they are not needed to retrieve all non-zero entries in `M`. +This occurs when the entries in a row (or column) are fully determined by the non-zero entries in the columns (or rows). +""" +function bicoloring end + """ NoColoringAlgorithm <: AbstractColoringAlgorithm @@ -168,6 +186,7 @@ struct NoColoringAlgorithm <: AbstractColoringAlgorithm end column_coloring(M::AbstractMatrix, ::NoColoringAlgorithm) = 1:size(M, 2) row_coloring(M::AbstractMatrix, ::NoColoringAlgorithm) = 1:size(M, 1) symmetric_coloring(M::AbstractMatrix, ::NoColoringAlgorithm) = 1:size(M, 1) +bicoloring(M::AbstractMatrix, ::NoColoringAlgorithm) = 1:size(M, 1), 1:size(M, 2) ## Sparse backend diff --git a/test/runtests.jl b/test/runtests.jl index 2e3f3e7..00887a3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -16,7 +16,8 @@ using ADTypes: dense_ad, coloring_algorithm, column_coloring, row_coloring, - symmetric_coloring + symmetric_coloring, + bicoloring using Aqua: Aqua using ChainRulesCore: ChainRulesCore, RuleConfig, HasForwardsMode, HasReverseMode, diff --git a/test/sparse.jl b/test/sparse.jl index 10c1c01..31d7b1a 100644 --- a/test/sparse.jl +++ b/test/sparse.jl @@ -159,4 +159,13 @@ end @test sv isa AbstractVector{<:Integer} @test length(sv) == size(M, 1) == size(M, 2) @test allunique(sv) + + M = rand(3, 4) + brv, bcv = bicoloring(M, ca) + @test brv isa AbstractVector{<:Integer} + @test bcv isa AbstractVector{<:Integer} + @test length(brv) == size(M, 1) + @test length(bcv) == size(M, 2) + @test allunique(brv) + @test allunique(bcv) end