From 7e3d12321728b0418d8541f4675ad0cf05693cbf Mon Sep 17 00:00:00 2001 From: Guillaume Dalle <22795598+gdalle@users.noreply.github.com> Date: Fri, 27 Sep 2024 23:47:36 +0200 Subject: [PATCH 1/2] Implement ConstantColoringAlgorithm --- docs/src/api.md | 1 + src/SparseMatrixColorings.jl | 2 + src/constant.jl | 73 ++++++++++++++++++++++++++++++++++++ test/constant.jl | 31 +++++++++++++++ test/runtests.jl | 3 ++ 5 files changed, 110 insertions(+) create mode 100644 src/constant.jl create mode 100644 test/constant.jl diff --git a/docs/src/api.md b/docs/src/api.md index 94c3dc9..1e70f6c 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -17,6 +17,7 @@ SparseMatrixColorings coloring ColoringProblem GreedyColoringAlgorithm +ConstantColoringAlgorithm ``` ## Result analysis diff --git a/src/SparseMatrixColorings.jl b/src/SparseMatrixColorings.jl index 9845f09..0fe6e6d 100644 --- a/src/SparseMatrixColorings.jl +++ b/src/SparseMatrixColorings.jl @@ -49,12 +49,14 @@ include("coloring.jl") include("result.jl") include("matrices.jl") include("interface.jl") +include("constant.jl") include("decompression.jl") include("check.jl") include("examples.jl") export NaturalOrder, RandomOrder, LargestFirst export ColoringProblem, GreedyColoringAlgorithm, AbstractColoringResult +export ConstantColoringAlgorithm export coloring export column_colors, row_colors export column_groups, row_groups diff --git a/src/constant.jl b/src/constant.jl new file mode 100644 index 0000000..184dfda --- /dev/null +++ b/src/constant.jl @@ -0,0 +1,73 @@ +""" + ConstantColoringAlgorithm{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`](@ref), 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 on `partition`). + +!!! warning + 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. +""" +struct ConstantColoringAlgorithm{ + partition,M<:AbstractMatrix,R<:AbstractColoringResult{:nonsymmetric,partition,:direct} +} <: ADTypes.AbstractColoringAlgorithm + matrix_template::M + color::Vector{Int} + result::R +end + +function ConstantColoringAlgorithm{:column}( + matrix_template::AbstractMatrix, color::Vector{Int} +) + S = convert(SparseMatrixCSC, matrix_template) + result = ColumnColoringResult(S, color) + M, R = typeof(matrix_template), typeof(result) + return ConstantColoringAlgorithm{:column,M,R}(matrix_template, color, result) +end + +function ConstantColoringAlgorithm{:row}( + matrix_template::AbstractMatrix, color::Vector{Int} +) + S = convert(SparseMatrixCSC, matrix_template) + result = RowColoringResult(S, color) + M, R = typeof(matrix_template), typeof(result) + return ConstantColoringAlgorithm{:row,M,R}(matrix_template, color, result) +end + +function ConstantColoringAlgorithm( + matrix_template::AbstractMatrix, color::Vector{Int}; partition=:column +) + return ConstantColoringAlgorithm{partition}(matrix_template, color) +end + +function coloring( + A::AbstractMatrix, + ::ColoringProblem{:nonsymmetric,partition}, + algo::ConstantColoringAlgorithm{partition}; + decompression_eltype::Type=Float64, + symmetric_pattern::Bool=false, +) where {partition} + @compat (; matrix_template, result) = algo + if size(A) != size(matrix_template) + throw( + DimensionMismatch( + "`ConstantColoringAlgorithm` expected matrix of size $(size(matrix_template)) but got matrix of size $(size(A))", + ), + ) + else + return result + end +end diff --git a/test/constant.jl b/test/constant.jl new file mode 100644 index 0000000..d6bc4f7 --- /dev/null +++ b/test/constant.jl @@ -0,0 +1,31 @@ +using SparseMatrixColorings +using Test + +matrix_template = ones(100, 200) + +@testset "Column coloring" begin + problem = ColoringProblem(; structure=:nonsymmetric, partition=:column) + color = rand(1:5, size(matrix_template, 2)) + algo = ConstantColoringAlgorithm(matrix_template, color; partition=:column) + wrong_algo = ConstantColoringAlgorithm(matrix_template, color; partition=:row) + @test_throws DimensionMismatch coloring(transpose(matrix_template), problem, algo) + @test_throws MethodError coloring(matrix_template, problem, wrong_algo) + result = coloring(matrix_template, problem, algo) + @test column_colors(result) == color +end + +@testset "Row coloring" begin + problem = ColoringProblem(; structure=:nonsymmetric, partition=:row) + color = rand(1:5, size(matrix_template, 1)) + algo = ConstantColoringAlgorithm(matrix_template, color; partition=:row) + @test_throws DimensionMismatch coloring(transpose(matrix_template), problem, algo) + result = coloring(matrix_template, problem, algo) + @test row_colors(result) == color +end + +@testset "Symmetric coloring" begin + wrong_problem = ColoringProblem(; structure=:symmetric, partition=:column) + color = rand(1:5, size(matrix_template, 2)) + algo = ConstantColoringAlgorithm(matrix_template, color; partition=:column) + @test_throws MethodError coloring(matrix_template, wrong_problem, algo) +end diff --git a/test/runtests.jl b/test/runtests.jl index d9cc5a9..51ed33a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -42,6 +42,9 @@ include("utils.jl") @testset "Constructors" begin include("constructors.jl") end + @testset "Constant coloring" begin + include("constant.jl") + end end @testset verbose = true "Correctness" begin @testset "Small instances" begin From a86fbf89504b8eb81ec2199b5d03c83b52746ea6 Mon Sep 17 00:00:00 2001 From: Guillaume Dalle <22795598+gdalle@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:22:07 +0200 Subject: [PATCH 2/2] Improve docs and add ADTypes --- src/constant.jl | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ test/constant.jl | 6 +++++ 2 files changed, 63 insertions(+) diff --git a/src/constant.jl b/src/constant.jl index 184dfda..046a1b0 100644 --- a/src/constant.jl +++ b/src/constant.jl @@ -20,6 +20,49 @@ Indeed, for symmetric coloring problems, we need more than just the vector of co 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 + +```jldoctest +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`](@extref ADTypes.AbstractColoringAlgorithm), which means the following methods are also applicable (although they will error if the kind of coloring demanded not consistent): + +- [`ADTypes.column_coloring`](@extref ADTypes.column_coloring) +- [`ADTypes.row_coloring`](@extref ADTypes.row_coloring) """ struct ConstantColoringAlgorithm{ partition,M<:AbstractMatrix,R<:AbstractColoringResult{:nonsymmetric,partition,:direct} @@ -71,3 +114,17 @@ function coloring( return result end end + +function ADTypes.column_coloring( + A::AbstractMatrix, algo::ConstantColoringAlgorithm{:column} +) + problem = ColoringProblem{:nonsymmetric,:column}() + result = coloring(A, problem, algo) + return column_colors(result) +end + +function ADTypes.row_coloring(A::AbstractMatrix, algo::ConstantColoringAlgorithm) + problem = ColoringProblem{:nonsymmetric,:row}() + result = coloring(A, problem, algo) + return row_colors(result) +end diff --git a/test/constant.jl b/test/constant.jl index d6bc4f7..5de881b 100644 --- a/test/constant.jl +++ b/test/constant.jl @@ -1,3 +1,4 @@ +using ADTypes: ADTypes using SparseMatrixColorings using Test @@ -12,6 +13,8 @@ matrix_template = ones(100, 200) @test_throws MethodError coloring(matrix_template, problem, wrong_algo) result = coloring(matrix_template, problem, algo) @test column_colors(result) == color + @test ADTypes.column_coloring(matrix_template, algo) == color + @test_throws MethodError ADTypes.row_coloring(matrix_template, algo) end @testset "Row coloring" begin @@ -21,6 +24,8 @@ end @test_throws DimensionMismatch coloring(transpose(matrix_template), problem, algo) result = coloring(matrix_template, problem, algo) @test row_colors(result) == color + @test ADTypes.row_coloring(matrix_template, algo) == color + @test_throws MethodError ADTypes.column_coloring(matrix_template, algo) end @testset "Symmetric coloring" begin @@ -28,4 +33,5 @@ end color = rand(1:5, size(matrix_template, 2)) algo = ConstantColoringAlgorithm(matrix_template, color; partition=:column) @test_throws MethodError coloring(matrix_template, wrong_problem, algo) + @test_throws MethodError ADTypes.symmetric_coloring(matrix_template, algo) end