From b20b0a60ea90d3c480c54514ae0103af341ccef4 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Sun, 9 Jun 2024 22:59:01 -0400 Subject: [PATCH 1/5] Upgrade ColPack.jl --- Project.toml | 8 +++--- docs/src/tutorial.md | 2 +- examples/Project.toml | 8 ++++++ examples/coloring.jl | 37 ++++++++++++++++++++++++++++ src/ColPack.jl | 1 + src/colpackcoloring.jl | 56 +++++++++++------------------------------- src/libcolpack.jl | 53 +++++++++++++++++++++++++++++++++++++++ src/method.jl | 16 ++++++++++++ test/functionality.jl | 2 +- 9 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 examples/Project.toml create mode 100644 examples/coloring.jl create mode 100644 src/libcolpack.jl diff --git a/Project.toml b/Project.toml index 5d2f078..8d0a3ed 100644 --- a/Project.toml +++ b/Project.toml @@ -10,8 +10,8 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] -ColPack_jll = "0.3.0" -LinearAlgebra = "1" -Random = "1" -SparseArrays = "1" +ColPack_jll = "0.4.0" +LinearAlgebra = "1.6" +Random = "1.6" +SparseArrays = "1.6" julia = "1.6" diff --git a/docs/src/tutorial.md b/docs/src/tutorial.md index 947d69a..a809da7 100644 --- a/docs/src/tutorial.md +++ b/docs/src/tutorial.md @@ -27,7 +27,7 @@ julia> adjJ = ColPack.matrix2adjmatrix(J; partition_by_rows=false) julia> coloring = ColPackColoring(adjJ, d1_coloring(), natural_ordering()); julia> colors = get_colors(coloring) -5-element Vector{Int64}: +5-element Vector{Int32}: 1 2 1 diff --git a/examples/Project.toml b/examples/Project.toml new file mode 100644 index 0000000..4c69167 --- /dev/null +++ b/examples/Project.toml @@ -0,0 +1,8 @@ +[deps] +ColPack = "ffa27691-3a59-46ab-a8d4-551f45b8d401" +ColPack_jll = "f218ff0c-cb54-5151-80c4-c0f62c730ce6" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MatrixMarket = "4d4711f2-db25-561a-b6b3-d35e7d4047d3" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804" +SuiteSparseMatrixCollection = "ac199af8-68bc-55b8-82c4-7abd6f96ed98" diff --git a/examples/coloring.jl b/examples/coloring.jl new file mode 100644 index 0000000..8a03344 --- /dev/null +++ b/examples/coloring.jl @@ -0,0 +1,37 @@ +using ColPack +using SuiteSparseMatrixCollection +using MatrixMarket +using SparseArrays +using SparseDiffTools +using LinearAlgebra + +ssmc = ssmc_db() +matrices = ssmc_matrices(ssmc, "Bodendiek", "CurlCurl_0") +folders = fetch_ssmc(matrices, format="MM") +paths = joinpath.(folders, matrices.name .* ".mtx") +A = MatrixMarket.mmread(paths[1]) + +orderings = Vector{ColoringOrder}() +push!(orderings, natural_ordering()) +push!(orderings, largest_first_ordering()) +push!(orderings, dynamic_largest_first_ordering()) +push!(orderings, distance_two_largest_first_ordering()) +push!(orderings, smallest_last_ordering()) +push!(orderings, distance_two_smallest_last_ordering()) +push!(orderings, incidence_degree_ordering()) +push!(orderings, distance_two_incidence_degree_ordering()) +push!(orderings, random_ordering()) + +@time sparsediff_coloring = SparseDiffTools.matrix_colors(A) +ncolors_sdt = maximum(sparsediff_coloring) + +method = ColPack.d1_coloring() +verbose = false +@time colpack_coloring = ColPackColoring(paths[1], method, random_ordering(); verbose) + +for ordering in orderings + colpack_coloring = ColPackColoring(paths[1], method, ordering; verbose) +end + +colors_colpack = get_colors(colpack_coloring) +ncolors_colpack = maximum(colors_colpack) diff --git a/src/ColPack.jl b/src/ColPack.jl index 2916372..2a69a8d 100644 --- a/src/ColPack.jl +++ b/src/ColPack.jl @@ -8,6 +8,7 @@ using SparseArrays # Definitions +include("libcolpack.jl") include("method.jl") include("order.jl") include("utils.jl") diff --git a/src/colpackcoloring.jl b/src/colpackcoloring.jl index 068eca6..f70681a 100644 --- a/src/colpackcoloring.jl +++ b/src/colpackcoloring.jl @@ -40,10 +40,7 @@ mutable struct ColPackColoring csr::Union{Vector{Ptr{Cuint}},Nothing} end -function free_coloring(g::ColPackColoring) - @ccall libcolpack.free_coloring(g.refColPack::Ptr{Cvoid})::Cvoid - return nothing -end +Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackColoring) = coloring.refColPack[] function ColPackColoring( filename::AbstractString, @@ -51,21 +48,12 @@ function ColPackColoring( order::ColoringOrder; verbose::Bool=false, ) - reflen = Vector{Cint}([Cint(0)]) refColPack = Ref{Ptr{Cvoid}}(C_NULL) - ret = @ccall libcolpack.build_coloring( - refColPack::Ptr{Cvoid}, - reflen::Ptr{Cint}, - filename::Cstring, - method.method::Cstring, - order.order::Cstring, - verbose::Cint, - )::Cint - if ret == 0 - error("ColPack coloring failed.") - end - - g = ColPackColoring(refColPack, zeros(Int, reflen[]), method, order, nothing) + reflen = Ref{Cint}(0) + ret = build_coloring_from_file(refColPack, reflen, filename, method.method, order.order, verbose) + (ret == 0) && error("ColPack coloring failed.") + coloring = zeros(Cint, reflen[]) + g = ColPackColoring(refColPack, coloring, method, order, nothing) finalizer(free_coloring, g) return g end @@ -92,36 +80,22 @@ function ColPackColoring( nrows = size(M, 2) reflen = Ref{Cint}(0) refColPack = Ref{Ptr{Cvoid}}(C_NULL) - ret = @ccall libcolpack.build_coloring_from_csr( - refColPack::Ptr{Cvoid}, - reflen::Ptr{Cint}, - csr::Ref{Ptr{Cuint}}, - nrows::Cint, - method.method::Cstring, - order.order::Cstring, - verbose::Cint, - )::Cint - if ret == 0 - error("ColPack coloring failed.") - end + ret = build_coloring_from_csr(refColPack, reflen, csr, nrows, method.method, order.order, verbose) + (ret == 0) && error("ColPack coloring failed.") - g = ColPackColoring(refColPack, zeros(Int, reflen[]), method, order, csr) + coloring = zeros(Cint, reflen[]) + g = ColPackColoring(refColPack, coloring, method, order, csr) finalizer(free_coloring, g) return g end """ - get_colors(coloring::ColPackColoring; verbose=false) + get_colors(coloring::ColPackColoring) Retrieve the colors from a [`ColPackColoring`](@ref) as a vector of integers. """ -function get_colors(coloring::ColPackColoring; verbose=false) - @ccall libcolpack.get_colors( - coloring.refColPack[]::Ptr{Cvoid}, - coloring.coloring::Ptr{Cdouble}, # TODO: should this be Cint? - coloring.method.method::Cstring, - verbose::Cint, - )::Cvoid - # Julia colorings should be base 1 - return coloring.coloring .+ 1 +function get_colors(coloring::ColPackColoring) + get_coloring(coloring.refColPack[], coloring.coloring) + coloring.coloring .+= Cint(1) + return coloring.coloring end diff --git a/src/libcolpack.jl b/src/libcolpack.jl new file mode 100644 index 0000000..4103e31 --- /dev/null +++ b/src/libcolpack.jl @@ -0,0 +1,53 @@ +function build_coloring_from_file(ref, len, _filename, _method, _order, verbose) + @ccall libcolpack.build_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, _filename::Cstring, + _method::Cstring, _order::Cstring, verbose::Cint)::Cint +end + +function build_bicoloring_from_file(ref, len1, len2, _filename, _method, _order, verbose) + @ccall libcolpack.build_bicoloring_from_file(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, _filename::Cstring, + _method::Cstring, _order::Cstring, verbose::Cint)::Cint +end + +function build_partial_coloring_from_file(ref, len1, len2, _filename, _method, _order, verbose) + @ccall libcolpack.build_partial_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, _filename::Cstring, + _method::Cstring, _order::Cstring, verbose::Cint)::Cint +end + +function build_coloring_from_csr(ref, len, csr, rowcount, _method, _order, verbose) + @ccall libcolpack.build_coloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, csr::Ptr{Ptr{Cuint}}, + rowcount::Cint, _method::Cstring, _order::Cstring, verbose::Cint)::Cint +end + +function build_bicoloring_from_csr(ref, len1, len2, csr, rowcount, colcount, _method, _order, verbose) + @ccall libcolpack.build_bicoloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, csr::Ptr{Ptr{Cuint}}, + rowcount::Cint, colcount::Cint, _method::Cstring, _order::Cstring, verbose::Cint)::Cint +end + +function build_partial_coloring_from_csr(ref, len1, len2, csr, rowcount, colcount, _method, _order, verbose) + @ccall libcolpack.build_partial_coloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, csr::Ptr{Ptr{Cuint}}, + rowcount::Cint, colcount::Cint, _method::Cstring, _order::Cstring, verbose::Cint)::Cint +end + +function get_coloring(ref, coloring) + @ccall libcolpack.get_coloring(ref::Ptr{Cvoid}, coloring::Ptr{Cint})::Cvoid +end + +function get_bicoloring(ref, left_coloring, right_coloring) + @ccall libcolpack.get_bicoloring(ref::Ptr{Cvoid}, left_coloring::Ptr{Cint}, right_coloring::Ptr{Cint})::Cvoid +end + +function get_partial_coloring(ref, left_coloring, right_coloring) + @ccall libcolpack.get_partial_coloring(ref::Ptr{Cvoid}, left_coloring::Ptr{Cint}, right_coloring::Ptr{Cint})::Cvoid +end + +function free_coloring(ref) + @ccall libcolpack.free_coloring(ref::Ptr{Cvoid})::Cvoid +end + +function free_bicoloring(ref) + @ccall libcolpack.free_bicoloring(ref::Ptr{Cvoid})::Cvoid +end + +function free_partial_coloring(ref) + @ccall libcolpack.free_partial_coloring(ref::Ptr{Cvoid})::Cvoid +end diff --git a/src/method.jl b/src/method.jl index 63f4a63..ba0ce72 100644 --- a/src/method.jl +++ b/src/method.jl @@ -13,6 +13,8 @@ Represent a [ColPack](https://github.com/CSCsw/ColPack)-compatible [coloring met - [`d2_coloring()`](@ref) - [`acyclic_coloring()`](@ref) - [`star_coloring()`](@ref) +- [`row_partial_d2_coloring()`](@ref) +- [`column_partial_d2_coloring()`](@ref) """ struct ColoringMethod method::String @@ -45,3 +47,17 @@ acyclic_coloring() = ColoringMethod("ACYCLIC") Shortcut for `ColoringMethod("STAR")`. """ star_coloring() = ColoringMethod("STAR") + +""" + row_partial_d2_coloring() + +Shortcut for `ColoringMethod("ROW_PARTIAL_DISTANCE_TWO")`. +""" +row_partial_d2_coloring() = ColoringMethod("ROW_PARTIAL_DISTANCE_TWO") + +""" + column_partial_d2_coloring() + +Shortcut for `ColoringMethod("COLUMN_PARTIAL_DISTANCE_TWO")`. +""" +column_partial_d2_coloring() = ColoringMethod("COLUMN_PARTIAL_DISTANCE_TWO") diff --git a/test/functionality.jl b/test/functionality.jl index e0f70d8..3921d20 100644 --- a/test/functionality.jl +++ b/test/functionality.jl @@ -21,7 +21,7 @@ push!(orderings, incidence_degree_ordering()) push!(orderings, distance_two_incidence_degree_ordering()) # push!(orderings, random_ordering()) -ncolors = Vector{Int}() +ncolors = Vector{Cint}() push!(ncolors, 7) push!(ncolors, 7) From 4e1f9408ae6fc410d1c7b44af298636af00eeebd Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Tue, 11 Jun 2024 00:00:27 -0400 Subject: [PATCH 2/5] Use ColPack_jll.jl v0.4.0 --- examples/coloring.jl | 27 ++++++ src/ColPack.jl | 8 +- src/colpack_bicoloring.jl | 73 ++++++++++++++ ...colpackcoloring.jl => colpack_coloring.jl} | 15 ++- src/colpack_partial_coloring.jl | 97 +++++++++++++++++++ src/libcolpack.jl | 53 +++++----- src/method.jl | 32 ++++++ test/functionality.jl | 20 +++- 8 files changed, 287 insertions(+), 38 deletions(-) create mode 100644 src/colpack_bicoloring.jl rename src/{colpackcoloring.jl => colpack_coloring.jl} (87%) create mode 100644 src/colpack_partial_coloring.jl diff --git a/examples/coloring.jl b/examples/coloring.jl index 8a03344..b5a4872 100644 --- a/examples/coloring.jl +++ b/examples/coloring.jl @@ -35,3 +35,30 @@ end colors_colpack = get_colors(colpack_coloring) ncolors_colpack = maximum(colors_colpack) + +method = row_partial_d2_coloring() +@time colpack_partial_coloring1 = ColPackPartialColoring(paths[1], method, natural_ordering(); verbose) +colors_row = get_colors(colpack_partial_coloring1) +maximum(colors_row) + +method = column_partial_d2_coloring() +@time colpack_partial_coloring2 = ColPackPartialColoring(paths[1], method, natural_ordering(); verbose) +colors_column = get_colors(colpack_partial_coloring2) +maximum(colors_column) + +method = row_partial_d2_coloring() +@time colpack_partial_coloring1 = ColPackPartialColoring(A, method, natural_ordering(); verbose) +colors_row2 = get_colors(colpack_partial_coloring1) +maximum(colors_row2) + +method = column_partial_d2_coloring() +@time colpack_partial_coloring2 = ColPackPartialColoring(A, method, natural_ordering(); verbose) +colors_column2 = get_colors(colpack_partial_coloring2) +maximum(colors_column2) + +method = implicit_star_bicoloring() +# method = explicit_star_bicoloring() +# method = explicit_modified_star_bicoloring() +# method = implicit_greedy_star_bicoloring() +@time colpack_bicoloring = ColPackBiColoring(paths[1], method, random_ordering(); verbose) +colors1, colors2 = get_colors(colpack_bicoloring) diff --git a/src/ColPack.jl b/src/ColPack.jl index 2a69a8d..03f120d 100644 --- a/src/ColPack.jl +++ b/src/ColPack.jl @@ -12,12 +12,16 @@ include("libcolpack.jl") include("method.jl") include("order.jl") include("utils.jl") -include("colpackcoloring.jl") +include("colpack_coloring.jl") +include("colpack_partial_coloring.jl") +include("colpack_bicoloring.jl") # Exports export ColoringMethod export d1_coloring, d2_coloring, acyclic_coloring, star_coloring +export row_partial_d2_coloring, column_partial_d2_coloring +export implicit_star_bicoloring, explicit_star_bicoloring, explicit_modified_star_bicoloring, implicit_greedy_star_bicoloring export ColoringOrder export natural_ordering, largest_first_ordering, dynamic_largest_first_ordering, distance_two_largest_first_ordering @@ -26,6 +30,6 @@ export random_ordering export matrix2adjmatrix -export ColPackColoring, get_colors +export ColPackColoring, ColPackPartialColoring, ColPackBiColoring, get_colors end #module diff --git a/src/colpack_bicoloring.jl b/src/colpack_bicoloring.jl new file mode 100644 index 0000000..5f5335c --- /dev/null +++ b/src/colpack_bicoloring.jl @@ -0,0 +1,73 @@ +""" + ColPackBiColoring + +Struct holding the parameters of a bicoloring as well as its results (which can be queried with [`get_colors`](@ref)). + +# Fields + +The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). + +# Constructors + + ColPackBiColoring( + filename::AbstractString, + method::ColoringMethod, + order::ColoringOrder; + verbose::Bool=false + ) + + ColPackBiColoring( + M::SparseMatrixCSC, + method::ColoringMethod, + order::ColoringOrder; + verbose::Bool=false + ) + +Perform the coloring of a matrix that is either given directly or read from a file. + +The users needs to specify a bicoloring `method` and an `order` on the vertices. + +# See also + +- [`ColoringMethod`](@ref) +- [`ColoringOrder`](@ref) +""" +mutable struct ColPackBiColoring + refColPack::Base.RefValue{Ptr{Cvoid}} + coloring1::Vector{Cint} + coloring2::Vector{Cint} + method::ColoringMethod + order::ColoringOrder +end + +Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackBiColoring) = coloring.refColPack[] + +function ColPackBiColoring( + filename::AbstractString, + method::ColoringMethod, + order::ColoringOrder; + verbose::Bool=false, +) + refColPack = Ref{Ptr{Cvoid}}(C_NULL) + reflen1 = Ref{Cint}(0) + reflen2 = Ref{Cint}(0) + ret = build_bicoloring_from_file(refColPack, reflen1, reflen2, filename, method.method, order.order, verbose) + (ret == 0) && error("ColPack bicoloring failed.") + coloring1 = zeros(Cint, reflen1[]) + coloring2 = zeros(Cint, reflen2[]) + g = ColPackBiColoring(refColPack, coloring1, coloring2, method, order) + finalizer(free_bicoloring, g) + return g +end + +""" + get_colors(coloring::ColPackBiColoring) + +Retrieve the colors from a [`ColPackBiColoring`](@ref) as vectors of integers. +""" +function get_colors(coloring::ColPackBiColoring) + get_bicoloring(coloring.refColPack[], coloring.coloring1, coloring.coloring2) + coloring.coloring1 .+= Cint(1) + coloring.coloring2 .+= Cint(1) + return coloring.coloring1, coloring.coloring2 +end diff --git a/src/colpackcoloring.jl b/src/colpack_coloring.jl similarity index 87% rename from src/colpackcoloring.jl rename to src/colpack_coloring.jl index f70681a..44e0841 100644 --- a/src/colpackcoloring.jl +++ b/src/colpack_coloring.jl @@ -37,7 +37,6 @@ mutable struct ColPackColoring coloring::Vector{Cint} method::ColoringMethod order::ColoringOrder - csr::Union{Vector{Ptr{Cuint}},Nothing} end Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackColoring) = coloring.refColPack[] @@ -53,18 +52,18 @@ function ColPackColoring( ret = build_coloring_from_file(refColPack, reflen, filename, method.method, order.order, verbose) (ret == 0) && error("ColPack coloring failed.") coloring = zeros(Cint, reflen[]) - g = ColPackColoring(refColPack, coloring, method, order, nothing) + g = ColPackColoring(refColPack, coloring, method, order) finalizer(free_coloring, g) return g end function ColPackColoring( - M::SparseMatrixCSC{VT,IT}, + M::SparseMatrixCSC, method::ColoringMethod, order::ColoringOrder; - verbose::Bool=false, -) where {VT,IT} - @assert issymmetric(M) + verbose::Bool=false +) + # We expect M to be symmetric. csr = Vector{Ref{Cuint}}() csr_mem = Vector{Vector{Cuint}}() for i in 1:(length(M.colptr) - 1) @@ -80,11 +79,11 @@ function ColPackColoring( nrows = size(M, 2) reflen = Ref{Cint}(0) refColPack = Ref{Ptr{Cvoid}}(C_NULL) - ret = build_coloring_from_csr(refColPack, reflen, csr, nrows, method.method, order.order, verbose) + ret = build_coloring_from_adolc(refColPack, reflen, csr, nrows, method.method, order.order, verbose) (ret == 0) && error("ColPack coloring failed.") coloring = zeros(Cint, reflen[]) - g = ColPackColoring(refColPack, coloring, method, order, csr) + g = ColPackColoring(refColPack, coloring, method, order) finalizer(free_coloring, g) return g end diff --git a/src/colpack_partial_coloring.jl b/src/colpack_partial_coloring.jl new file mode 100644 index 0000000..9a3530a --- /dev/null +++ b/src/colpack_partial_coloring.jl @@ -0,0 +1,97 @@ +""" + ColPackPartialColoring + +Struct holding the parameters of a partial coloring as well as its results (which can be queried with [`get_colors`](@ref)). + +# Fields + +The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). + +# Constructors + + ColPackPartialColoring( + filename::AbstractString, + method::ColoringMethod, + order::ColoringOrder; + verbose::Bool=false + ) + + ColPackPartialColoring( + M::SparseMatrixCSC, + method::ColoringMethod, + order::ColoringOrder; + verbose::Bool=false + ) + +Perform the partial coloring of a matrix that is either given directly or read from a file. + +The users needs to specify a partial coloring `method` and an `order` on the vertices. + +# See also + +- [`ColoringMethod`](@ref) +- [`ColoringOrder`](@ref) +""" +mutable struct ColPackPartialColoring + refColPack::Base.RefValue{Ptr{Cvoid}} + coloring::Vector{Cint} + method::ColoringMethod + order::ColoringOrder +end + +Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackPartialColoring) = coloring.refColPack[] + +function ColPackPartialColoring( + filename::AbstractString, + method::ColoringMethod, + order::ColoringOrder; + verbose::Bool=false, +) + refColPack = Ref{Ptr{Cvoid}}(C_NULL) + reflen = Ref{Cint}(0) + ret = build_partial_coloring_from_file(refColPack, reflen, filename, method.method, order.order, verbose) + (ret == 0) && error("ColPack partial coloring failed.") + coloring = zeros(Cint, reflen[]) + g = ColPackPartialColoring(refColPack, coloring, method, order) + finalizer(free_partial_coloring, g) + return g +end + +function ColPackPartialColoring( + M::SparseMatrixCSC, + method::ColoringMethod, + order::ColoringOrder; + verbose::Bool=false, +) + reflen = Ref{Cint}(0) + refColPack = Ref{Ptr{Cvoid}}(C_NULL) + nrows, ncols = size(M) + + # The CSC format of M is the CSR format of Mᵀ. + Mt_cols = Cint.(M.rowval) + Mt_rows = Cint.(M.colptr) + + # ColPack expects sparse CSR matrices with 0-based indexing. + Mt_cols .-= Cint(1) + Mt_rows .-= Cint(1) + + (method.method == "ROW_PARTIAL_DISTANCE_TWO") && (colpack_method = "COLUMN_PARTIAL_DISTANCE_TWO") + (method.method == "COLUMN_PARTIAL_DISTANCE_TWO") && (colpack_method = "ROW_PARTIAL_DISTANCE_TWO") + ret = build_partial_coloring_from_csr(refColPack, reflen, Mt_rows, Mt_cols, ncols, nrows, colpack_method, order.order, verbose) + (ret == 0) && error("ColPack partial coloring failed.") + coloring = zeros(Cint, reflen[]) + g = ColPackPartialColoring(refColPack, coloring, ColoringMethod(colpack_method), order) + finalizer(free_partial_coloring, g) + return g +end + +""" + get_colors(coloring::ColPackPartialColoring) + +Retrieve the colors from a [`ColPackPartialColoring`](@ref) as a vector of integers. +""" +function get_colors(coloring::ColPackPartialColoring) + get_partial_coloring(coloring.refColPack[], coloring.coloring) + coloring.coloring .+= Cint(1) + return coloring.coloring +end diff --git a/src/libcolpack.jl b/src/libcolpack.jl index 4103e31..300f33a 100644 --- a/src/libcolpack.jl +++ b/src/libcolpack.jl @@ -1,53 +1,58 @@ function build_coloring_from_file(ref, len, _filename, _method, _order, verbose) - @ccall libcolpack.build_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, _filename::Cstring, - _method::Cstring, _order::Cstring, verbose::Cint)::Cint + @ccall libcolpack.build_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, _filename::Ptr{Cchar}, + _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint +end + +function build_partial_coloring_from_file(ref, len, _filename, _method, _order, verbose) + @ccall libcolpack.build_partial_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, _filename::Ptr{Cchar}, + _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint end function build_bicoloring_from_file(ref, len1, len2, _filename, _method, _order, verbose) - @ccall libcolpack.build_bicoloring_from_file(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, _filename::Cstring, - _method::Cstring, _order::Cstring, verbose::Cint)::Cint + @ccall libcolpack.build_bicoloring_from_file(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, _filename::Ptr{Cchar}, + _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint end -function build_partial_coloring_from_file(ref, len1, len2, _filename, _method, _order, verbose) - @ccall libcolpack.build_partial_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, _filename::Cstring, - _method::Cstring, _order::Cstring, verbose::Cint)::Cint +function build_coloring_from_adolc(ref, len, adolc, rowcount, _method, _order, verbose) + @ccall libcolpack.build_coloring_from_adolc(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, adolc::Ptr{Ptr{Cuint}}, + rowcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint end -function build_coloring_from_csr(ref, len, csr, rowcount, _method, _order, verbose) - @ccall libcolpack.build_coloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, csr::Ptr{Ptr{Cuint}}, - rowcount::Cint, _method::Cstring, _order::Cstring, verbose::Cint)::Cint +function build_partial_coloring_from_adolc(ref, len, adolc, rowcount, colcount, _method, _order, verbose) + @ccall libcolpack.build_partial_coloring_from_adolc(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, adolc::Ptr{Ptr{Cuint}}, + rowcount::Cint, colcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint end -function build_bicoloring_from_csr(ref, len1, len2, csr, rowcount, colcount, _method, _order, verbose) - @ccall libcolpack.build_bicoloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, csr::Ptr{Ptr{Cuint}}, - rowcount::Cint, colcount::Cint, _method::Cstring, _order::Cstring, verbose::Cint)::Cint +function build_bicoloring_from_adolc(ref, len1, len2, adolc, rowcount, colcount, _method, _order, verbose) + @ccall libcolpack.build_bicoloring_from_adolc(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, adolc::Ptr{Ptr{Cuint}}, + rowcount::Cint, colcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint end -function build_partial_coloring_from_csr(ref, len1, len2, csr, rowcount, colcount, _method, _order, verbose) - @ccall libcolpack.build_partial_coloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, csr::Ptr{Ptr{Cuint}}, - rowcount::Cint, colcount::Cint, _method::Cstring, _order::Cstring, verbose::Cint)::Cint +function build_partial_coloring_from_csr(ref, len, rows, cols, rowcount, colcount, _method, _order, verbose) + @ccall libcolpack.build_partial_coloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, rows::Ptr{Cint}, cols::Ptr{Cint}, + rowcount::Cint, colcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint end function get_coloring(ref, coloring) @ccall libcolpack.get_coloring(ref::Ptr{Cvoid}, coloring::Ptr{Cint})::Cvoid end -function get_bicoloring(ref, left_coloring, right_coloring) - @ccall libcolpack.get_bicoloring(ref::Ptr{Cvoid}, left_coloring::Ptr{Cint}, right_coloring::Ptr{Cint})::Cvoid +function get_partial_coloring(ref, coloring) + @ccall libcolpack.get_partial_coloring(ref::Ptr{Cvoid}, coloring::Ptr{Cint})::Cvoid end -function get_partial_coloring(ref, left_coloring, right_coloring) - @ccall libcolpack.get_partial_coloring(ref::Ptr{Cvoid}, left_coloring::Ptr{Cint}, right_coloring::Ptr{Cint})::Cvoid +function get_bicoloring(ref, left_coloring, right_coloring) + @ccall libcolpack.get_bicoloring(ref::Ptr{Cvoid}, left_coloring::Ptr{Cint}, right_coloring::Ptr{Cint})::Cvoid end function free_coloring(ref) @ccall libcolpack.free_coloring(ref::Ptr{Cvoid})::Cvoid end -function free_bicoloring(ref) - @ccall libcolpack.free_bicoloring(ref::Ptr{Cvoid})::Cvoid -end - function free_partial_coloring(ref) @ccall libcolpack.free_partial_coloring(ref::Ptr{Cvoid})::Cvoid end + +function free_bicoloring(ref) + @ccall libcolpack.free_bicoloring(ref::Ptr{Cvoid})::Cvoid +end diff --git a/src/method.jl b/src/method.jl index ba0ce72..08115a6 100644 --- a/src/method.jl +++ b/src/method.jl @@ -15,6 +15,10 @@ Represent a [ColPack](https://github.com/CSCsw/ColPack)-compatible [coloring met - [`star_coloring()`](@ref) - [`row_partial_d2_coloring()`](@ref) - [`column_partial_d2_coloring()`](@ref) +- [`implicit_star_bicoloring()`](@ref) +- [`explicit_star_bicoloring()`](@ref) +- [`explicit_modified_star_bicoloring()`](@ref) +- [`implicit_greedy_star_bicoloring()`](@ref) """ struct ColoringMethod method::String @@ -61,3 +65,31 @@ row_partial_d2_coloring() = ColoringMethod("ROW_PARTIAL_DISTANCE_TWO") Shortcut for `ColoringMethod("COLUMN_PARTIAL_DISTANCE_TWO")`. """ column_partial_d2_coloring() = ColoringMethod("COLUMN_PARTIAL_DISTANCE_TWO") + +""" + implicit_star_bicoloring() + +Shortcut for `ColoringMethod("IMPLICIT_COVERING__STAR_BICOLORING")`. +""" +implicit_star_bicoloring() = ColoringMethod("IMPLICIT_COVERING__STAR_BICOLORING") + +""" + explicit_star_bicoloring() + +Shortcut for `ColoringMethod("EXPLICIT_COVERING__STAR_BICOLORING")`. +""" +explicit_star_bicoloring() = ColoringMethod("EXPLICIT_COVERING__STAR_BICOLORING") + +""" + explicit_modified_star_bicoloring() + +Shortcut for `ColoringMethod("EXPLICIT_COVERING__MODIFIED_STAR_BICOLORING")`. +""" +explicit_modified_star_bicoloring() = ColoringMethod("EXPLICIT_COVERING__MODIFIED_STAR_BICOLORING") + +""" + implicit_greedy_star_bicoloring() + +Shortcut for `ColoringMethod(IMPLICIT_COVERING__GREEDY_STAR_BICOLORING")`. +""" +implicit_greedy_star_bicoloring() = ColoringMethod("IMPLICIT_COVERING__GREEDY_STAR_BICOLORING") diff --git a/test/functionality.jl b/test/functionality.jl index 3921d20..696acf3 100644 --- a/test/functionality.jl +++ b/test/functionality.jl @@ -43,16 +43,28 @@ MatrixMarket.mmwrite(filename, A) verbose = false @testset "MatrixMarket API" begin - @testset "$ordering" for (i, ordering) in enumerate(orderings) + @testset "Coloring -- $ordering" for (i, ordering) in enumerate(orderings) coloring = ColPackColoring(filename, d1_coloring(), ordering; verbose=verbose) - @test length(unique(get_colors(coloring))) == ncolors[i] + @test maximum(get_colors(coloring)) == ncolors[i] + end + + @testset "Partial coloring -- $ordering" for (i, ordering) in enumerate(orderings) + row_coloring = ColPackPartialColoring(filename, row_partial_d2_coloring(), ordering; verbose=verbose) + column_coloring = ColPackPartialColoring(filename, column_partial_d2_coloring(), ordering; verbose=verbose) end end @testset "ADOL-C Compressed Row Storage" begin - @testset "$ordering" for (i, ordering) in enumerate(orderings) + @testset "Coloring -- $ordering" for (i, ordering) in enumerate(orderings) coloring = ColPackColoring(A, d1_coloring(), ordering; verbose=verbose) - @test length(unique(get_colors(coloring))) == ncolors[i] + @test maximum(get_colors(coloring)) == ncolors[i] + end +end + +@testset "CSR Storage" begin + @testset "Partial coloring -- $ordering" for (i, ordering) in enumerate(orderings) + row_coloring = ColPackPartialColoring(A, row_partial_d2_coloring(), ordering; verbose=verbose) + column_coloring = ColPackPartialColoring(A, column_partial_d2_coloring(), ordering; verbose=verbose) end end From 3836b4378151d70d75e406a52c2f9af90e89380b Mon Sep 17 00:00:00 2001 From: Guillaume Dalle <22795598+gdalle@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:11:42 +0200 Subject: [PATCH 3/5] Options defined by strings, systematic tests --- Project.toml | 4 +- README.md | 8 ++- docs/make.jl | 4 +- docs/src/api.md | 23 +------ docs/src/tutorial.md | 44 ------------- examples/Project.toml | 8 --- examples/coloring.jl | 64 ------------------- src/ColPack.jl | 28 ++++----- src/colpack_bicoloring.jl | 59 ++++++++++-------- src/colpack_coloring.jl | 75 ++++++++++++++-------- src/colpack_partial_coloring.jl | 93 +++++++++++++++++++--------- src/libcolpack.jl | 96 +++++++++++++++++++++++------ src/method.jl | 95 ---------------------------- src/options.jl | 63 +++++++++++++++++++ src/order.jl | 87 -------------------------- src/utils.jl | 61 ------------------ test/Project.toml | 1 - test/coloring.jl | 106 ++++++++++++++++++++++++++++++++ test/exceptions.jl | 43 +++++++++++++ test/functionality.jl | 84 ------------------------- test/runtests.jl | 7 ++- 21 files changed, 467 insertions(+), 586 deletions(-) delete mode 100644 docs/src/tutorial.md delete mode 100644 examples/Project.toml delete mode 100644 examples/coloring.jl delete mode 100644 src/method.jl create mode 100644 src/options.jl delete mode 100644 src/order.jl delete mode 100644 src/utils.jl create mode 100644 test/coloring.jl create mode 100644 test/exceptions.jl delete mode 100644 test/functionality.jl diff --git a/Project.toml b/Project.toml index 8d0a3ed..92d468a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ColPack" uuid = "ffa27691-3a59-46ab-a8d4-551f45b8d401" -authors = ["Michel Schanen ", "Guillaume Dalle"] -version = "0.4.0" +authors = ["Michel Schanen ", "Alexis Montoison", "Guillaume Dalle"] +version = "0.5.0" [deps] ColPack_jll = "f218ff0c-cb54-5151-80c4-c0f62c730ce6" diff --git a/README.md b/README.md index 473a13d..2e5ea5c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Stable Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://exanauts.github.io/ColPack.jl/stable/) [![Dev Documentation](https://img.shields.io/badge/docs-dev-blue.svg)](https://exanauts.github.io/ColPack.jl/dev/) -This is the Julia interface to [ColPack](https://github.com/CSCsw/ColPack) for graph and matrix coloring. +A Julia interface to the C++ library [ColPack](https://github.com/CSCsw/ColPack) for graph and sparse matrix coloring. ## Getting started @@ -14,10 +14,12 @@ You can install this package by running the following command in a Julia Pkg REP pkg> add ColPack ``` -Take a look at the tutorial in the documentation to get a feel for what you can do. - ## Mathematical background To understand the link between graph coloring and automatic differentiation, read the following survey: > [_What Color Is Your Jacobian? Graph Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005) + +The ColPack library itself is described in: + +> [_ColPack: Software for graph coloring and related problems in scientific computing_](https://dl.acm.org/doi/10.1145/2513109.2513110), Gebremedhin et al. (2012) \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index ef236f6..75f826c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,10 +5,10 @@ cp(joinpath(@__DIR__, "..", "README.md"), joinpath(@__DIR__, "src", "index.md"); makedocs(; modules=[ColPack], - authors="Michel Schanen, Guillaume Dalle", + authors="Michel Schanen, Alexis Montoison, Guillaume Dalle", sitename="ColPack.jl", format=Documenter.HTML(), - pages=["Home" => "index.md", "Tutorial" => "tutorial.md", "API reference" => "api.md"], + pages=["Home" => "index.md", "API reference" => "api.md"], ) deploydocs(; repo="github.com/exanauts/ColPack.jl", devbranch="master") diff --git a/docs/src/api.md b/docs/src/api.md index 19e72ec..40ac387 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -1,30 +1,13 @@ -```@meta -CollapsedDocStrings = true -``` - # API reference -## Entry points - -```@autodocs -Modules = [ColPack] -Pages = ["colpackcoloring.jl", "utils.jl"] -Private = false -``` - -## Coloring method - -```@autodocs -Modules = [ColPack] -Pages = ["method.jl"] -Private = false +```@meta +CollapsedDocStrings = true ``` -## Coloring order +## Public ```@autodocs Modules = [ColPack] -Pages = ["order.jl"] Private = false ``` diff --git a/docs/src/tutorial.md b/docs/src/tutorial.md deleted file mode 100644 index a809da7..0000000 --- a/docs/src/tutorial.md +++ /dev/null @@ -1,44 +0,0 @@ -# Tutorial - -## Jacobian coloring - -```jldoctest tuto -julia> using ColPack, SparseArrays -``` - -```jldoctest tuto -julia> J = sparse([ - 1 1 0 0 0 - 0 0 1 0 0 - 0 1 0 1 0 - 0 0 0 1 1 - ]); - -julia> adjJ = ColPack.matrix2adjmatrix(J; partition_by_rows=false) -5×5 SparseMatrixCSC{Float64, UInt32} with 6 stored entries: - ⋅ 1.0 ⋅ ⋅ ⋅ - 1.0 ⋅ ⋅ 1.0 ⋅ - ⋅ ⋅ ⋅ ⋅ ⋅ - ⋅ 1.0 ⋅ ⋅ 1.0 - ⋅ ⋅ ⋅ 1.0 ⋅ -``` - -```jldoctest tuto -julia> coloring = ColPackColoring(adjJ, d1_coloring(), natural_ordering()); - -julia> colors = get_colors(coloring) -5-element Vector{Int32}: - 1 - 2 - 1 - 1 - 2 - -julia> length(unique(colors)) == 2 -true -``` - -## Hessian coloring - -!!! warning - Work in progress \ No newline at end of file diff --git a/examples/Project.toml b/examples/Project.toml deleted file mode 100644 index 4c69167..0000000 --- a/examples/Project.toml +++ /dev/null @@ -1,8 +0,0 @@ -[deps] -ColPack = "ffa27691-3a59-46ab-a8d4-551f45b8d401" -ColPack_jll = "f218ff0c-cb54-5151-80c4-c0f62c730ce6" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -MatrixMarket = "4d4711f2-db25-561a-b6b3-d35e7d4047d3" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804" -SuiteSparseMatrixCollection = "ac199af8-68bc-55b8-82c4-7abd6f96ed98" diff --git a/examples/coloring.jl b/examples/coloring.jl deleted file mode 100644 index b5a4872..0000000 --- a/examples/coloring.jl +++ /dev/null @@ -1,64 +0,0 @@ -using ColPack -using SuiteSparseMatrixCollection -using MatrixMarket -using SparseArrays -using SparseDiffTools -using LinearAlgebra - -ssmc = ssmc_db() -matrices = ssmc_matrices(ssmc, "Bodendiek", "CurlCurl_0") -folders = fetch_ssmc(matrices, format="MM") -paths = joinpath.(folders, matrices.name .* ".mtx") -A = MatrixMarket.mmread(paths[1]) - -orderings = Vector{ColoringOrder}() -push!(orderings, natural_ordering()) -push!(orderings, largest_first_ordering()) -push!(orderings, dynamic_largest_first_ordering()) -push!(orderings, distance_two_largest_first_ordering()) -push!(orderings, smallest_last_ordering()) -push!(orderings, distance_two_smallest_last_ordering()) -push!(orderings, incidence_degree_ordering()) -push!(orderings, distance_two_incidence_degree_ordering()) -push!(orderings, random_ordering()) - -@time sparsediff_coloring = SparseDiffTools.matrix_colors(A) -ncolors_sdt = maximum(sparsediff_coloring) - -method = ColPack.d1_coloring() -verbose = false -@time colpack_coloring = ColPackColoring(paths[1], method, random_ordering(); verbose) - -for ordering in orderings - colpack_coloring = ColPackColoring(paths[1], method, ordering; verbose) -end - -colors_colpack = get_colors(colpack_coloring) -ncolors_colpack = maximum(colors_colpack) - -method = row_partial_d2_coloring() -@time colpack_partial_coloring1 = ColPackPartialColoring(paths[1], method, natural_ordering(); verbose) -colors_row = get_colors(colpack_partial_coloring1) -maximum(colors_row) - -method = column_partial_d2_coloring() -@time colpack_partial_coloring2 = ColPackPartialColoring(paths[1], method, natural_ordering(); verbose) -colors_column = get_colors(colpack_partial_coloring2) -maximum(colors_column) - -method = row_partial_d2_coloring() -@time colpack_partial_coloring1 = ColPackPartialColoring(A, method, natural_ordering(); verbose) -colors_row2 = get_colors(colpack_partial_coloring1) -maximum(colors_row2) - -method = column_partial_d2_coloring() -@time colpack_partial_coloring2 = ColPackPartialColoring(A, method, natural_ordering(); verbose) -colors_column2 = get_colors(colpack_partial_coloring2) -maximum(colors_column2) - -method = implicit_star_bicoloring() -# method = explicit_star_bicoloring() -# method = explicit_modified_star_bicoloring() -# method = implicit_greedy_star_bicoloring() -@time colpack_bicoloring = ColPackBiColoring(paths[1], method, random_ordering(); verbose) -colors1, colors2 = get_colors(colpack_bicoloring) diff --git a/src/ColPack.jl b/src/ColPack.jl index 03f120d..fcf0d57 100644 --- a/src/ColPack.jl +++ b/src/ColPack.jl @@ -1,3 +1,15 @@ +""" + ColPack + +A Julia interface to the C++ library [ColPack](https://github.com/CSCsw/ColPack) for graph and sparse matrix coloring. + +# Exports + +- [`ColPackColoring`](@ref) +- [`ColPackPartialColoring`](@ref) +- [`ColPackBiColoring`](@ref) +- [`get_colors`](@ref) +""" module ColPack # Imports @@ -9,27 +21,13 @@ using SparseArrays # Definitions include("libcolpack.jl") -include("method.jl") -include("order.jl") -include("utils.jl") +include("options.jl") include("colpack_coloring.jl") include("colpack_partial_coloring.jl") include("colpack_bicoloring.jl") # Exports -export ColoringMethod -export d1_coloring, d2_coloring, acyclic_coloring, star_coloring -export row_partial_d2_coloring, column_partial_d2_coloring -export implicit_star_bicoloring, explicit_star_bicoloring, explicit_modified_star_bicoloring, implicit_greedy_star_bicoloring - -export ColoringOrder -export natural_ordering, largest_first_ordering, dynamic_largest_first_ordering, distance_two_largest_first_ordering -export smallest_last_ordering, distance_two_smallest_last_ordering, incidence_degree_ordering, distance_two_incidence_degree_ordering -export random_ordering - -export matrix2adjmatrix - export ColPackColoring, ColPackPartialColoring, ColPackBiColoring, get_colors end #module diff --git a/src/colpack_bicoloring.jl b/src/colpack_bicoloring.jl index 5f5335c..fe80eff 100644 --- a/src/colpack_bicoloring.jl +++ b/src/colpack_bicoloring.jl @@ -3,55 +3,58 @@ Struct holding the parameters of a bicoloring as well as its results (which can be queried with [`get_colors`](@ref)). -# Fields - -The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). - # Constructors - ColPackBiColoring( - filename::AbstractString, - method::ColoringMethod, - order::ColoringOrder; - verbose::Bool=false +ColPackBiColoring( + filename::AbstractString, + method::String, + order::String; + verbose::Bool=false ) - + ColPackBiColoring( M::SparseMatrixCSC, - method::ColoringMethod, - order::ColoringOrder; + method::String, + order::String; verbose::Bool=false ) + +Perform the coloring of a matrix that is either given directly or read from a `.mtx` file. -Perform the coloring of a matrix that is either given directly or read from a file. - -The users needs to specify a bicoloring `method` and an `order` on the vertices. +The users needs to specify -# See also +- a bicoloring `method` among `$BICOLORING_METHODS` +- an `order` on the vertices among `$BICOLORING_ORDERS` -- [`ColoringMethod`](@ref) -- [`ColoringOrder`](@ref) +# Fields + +The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). """ mutable struct ColPackBiColoring refColPack::Base.RefValue{Ptr{Cvoid}} coloring1::Vector{Cint} coloring2::Vector{Cint} - method::ColoringMethod - order::ColoringOrder + method::String + order::String end Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackBiColoring) = coloring.refColPack[] function ColPackBiColoring( - filename::AbstractString, - method::ColoringMethod, - order::ColoringOrder; - verbose::Bool=false, + filename::AbstractString, method::String, order::String; verbose::Bool=false ) + if !(method in BICOLORING_METHODS) + throw(ArgumentError("""Method "$method" is not in $BICOLORING_METHODS""")) + end + if !(order in BICOLORING_ORDERS) + throw(ArgumentError("""Order "$order" is not in $BICOLORING_ORDERS""")) + end refColPack = Ref{Ptr{Cvoid}}(C_NULL) reflen1 = Ref{Cint}(0) reflen2 = Ref{Cint}(0) - ret = build_bicoloring_from_file(refColPack, reflen1, reflen2, filename, method.method, order.order, verbose) + ret = build_bicoloring_from_file( + refColPack, reflen1, reflen2, filename, method, order, verbose + ) (ret == 0) && error("ColPack bicoloring failed.") coloring1 = zeros(Cint, reflen1[]) coloring2 = zeros(Cint, reflen2[]) @@ -63,10 +66,14 @@ end """ get_colors(coloring::ColPackBiColoring) -Retrieve the colors from a [`ColPackBiColoring`](@ref) as vectors of integers. +Retrieve the colors from a [`ColPackBiColoring`](@ref) as two vectors of integers. """ function get_colors(coloring::ColPackBiColoring) get_bicoloring(coloring.refColPack[], coloring.coloring1, coloring.coloring2) + #= + Zero is a neutral color in bicoloring, it may make sense to keep it. + I am not yet sure how the coloring vectors are defined. + =# coloring.coloring1 .+= Cint(1) coloring.coloring2 .+= Cint(1) return coloring.coloring1, coloring.coloring2 diff --git a/src/colpack_coloring.jl b/src/colpack_coloring.jl index 44e0841..943cdde 100644 --- a/src/colpack_coloring.jl +++ b/src/colpack_coloring.jl @@ -3,53 +3,72 @@ Struct holding the parameters of a coloring as well as its results (which can be queried with [`get_colors`](@ref)). -# Fields - -The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). - # Constructors ColPackColoring( filename::AbstractString, - method::ColoringMethod, - order::ColoringOrder; + method::String, + order::String; verbose::Bool=false ) ColPackColoring( M::SparseMatrixCSC, - method::ColoringMethod, - order::ColoringOrder; + method::String, + order::String; verbose::Bool=false ) -Perform the coloring of a matrix that is either given directly or read from a file. +Perform the coloring of a matrix that is either given directly or read from a `.mtx` file. + +The users needs to specify + +- a coloring `method` among `$COLORING_METHODS` +- an `order` on the vertices among `$COLORING_ORDERS` + +# Example + +```jldoctest +julia> using ColPack, SparseArrays -The users needs to specify a coloring `method` and an `order` on the vertices. +julia> H = sparse([1 1 1; 1 1 0; 1 0 1]) +3×3 SparseMatrixCSC{Int64, Int64} with 7 stored entries: + 1 1 1 + 1 1 ⋅ + 1 ⋅ 1 -# See also +julia> get_colors(ColPackColoring(H, "STAR", "NATURAL")) +3-element Vector{Int32}: + 1 + 2 + 2 +``` -- [`ColoringMethod`](@ref) -- [`ColoringOrder`](@ref) +# Fields + +The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). """ mutable struct ColPackColoring refColPack::Base.RefValue{Ptr{Cvoid}} coloring::Vector{Cint} - method::ColoringMethod - order::ColoringOrder + method::String + order::String end Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackColoring) = coloring.refColPack[] function ColPackColoring( - filename::AbstractString, - method::ColoringMethod, - order::ColoringOrder; - verbose::Bool=false, + filename::AbstractString, method::String, order::String; verbose::Bool=false ) + if !(method in COLORING_METHODS) + throw(ArgumentError("""Method "$method" is not in $COLORING_METHODS""")) + end + if !(order in COLORING_ORDERS) + throw(ArgumentError("""Order "$order" is not in $COLORING_ORDERS""")) + end refColPack = Ref{Ptr{Cvoid}}(C_NULL) reflen = Ref{Cint}(0) - ret = build_coloring_from_file(refColPack, reflen, filename, method.method, order.order, verbose) + ret = build_coloring_from_file(refColPack, reflen, filename, method, order, verbose) (ret == 0) && error("ColPack coloring failed.") coloring = zeros(Cint, reflen[]) g = ColPackColoring(refColPack, coloring, method, order) @@ -58,11 +77,17 @@ function ColPackColoring( end function ColPackColoring( - M::SparseMatrixCSC, - method::ColoringMethod, - order::ColoringOrder; - verbose::Bool=false + M::SparseMatrixCSC, method::String, order::String; verbose::Bool=false ) + if !(method in COLORING_METHODS) + throw(ArgumentError("""Method "$method" is not in $COLORING_METHODS""")) + end + if !(order in COLORING_ORDERS) + throw(ArgumentError("""Order "$order" is not in $COLORING_ORDERS""")) + end + if size(M, 1) != size(M, 2) + throw(DimensionMismatch("Matrix must be square (and symmetric)")) + end # We expect M to be symmetric. csr = Vector{Ref{Cuint}}() csr_mem = Vector{Vector{Cuint}}() @@ -79,7 +104,7 @@ function ColPackColoring( nrows = size(M, 2) reflen = Ref{Cint}(0) refColPack = Ref{Ptr{Cvoid}}(C_NULL) - ret = build_coloring_from_adolc(refColPack, reflen, csr, nrows, method.method, order.order, verbose) + ret = build_coloring_from_adolc(refColPack, reflen, csr, nrows, method, order, verbose) (ret == 0) && error("ColPack coloring failed.") coloring = zeros(Cint, reflen[]) diff --git a/src/colpack_partial_coloring.jl b/src/colpack_partial_coloring.jl index 9a3530a..9c90632 100644 --- a/src/colpack_partial_coloring.jl +++ b/src/colpack_partial_coloring.jl @@ -3,53 +3,85 @@ Struct holding the parameters of a partial coloring as well as its results (which can be queried with [`get_colors`](@ref)). -# Fields - -The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). - # Constructors ColPackPartialColoring( filename::AbstractString, - method::ColoringMethod, - order::ColoringOrder; + method::String, + order::String; verbose::Bool=false ) ColPackPartialColoring( M::SparseMatrixCSC, - method::ColoringMethod, - order::ColoringOrder; + method::String, + order::String; verbose::Bool=false ) -Perform the partial coloring of a matrix that is either given directly or read from a file. +Perform the partial coloring of a matrix that is either given directly or read from a `.mtx` file. + +The users needs to specify: + +- a partial coloring `method` among `$PARTIAL_COLORING_METHODS` +- an `order` on the vertices among `$PARTIAL_COLORING_ORDERS` + +# Example + +```jldoctest +julia> using ColPack, SparseArrays -The users needs to specify a partial coloring `method` and an `order` on the vertices. +julia> J = sparse([1 0 1; 1 1 0]) +2×3 SparseMatrixCSC{Int64, Int64} with 4 stored entries: + 1 ⋅ 1 + 1 1 ⋅ -# See also +julia> get_colors(ColPackPartialColoring(J, "COLUMN_PARTIAL_DISTANCE_TWO", "NATURAL")) +3-element Vector{Int32}: + 1 + 2 + 2 +``` -- [`ColoringMethod`](@ref) -- [`ColoringOrder`](@ref) +# Fields + +The fields of this struct are not part of the public API, they are only useful to interface with the C++ library [ColPack](https://github.com/CSCsw/ColPack). """ mutable struct ColPackPartialColoring refColPack::Base.RefValue{Ptr{Cvoid}} coloring::Vector{Cint} - method::ColoringMethod - order::ColoringOrder + method::String + order::String +end + +function Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackPartialColoring) + return coloring.refColPack[] end -Base.unsafe_convert(::Type{Ptr{Cvoid}}, coloring::ColPackPartialColoring) = coloring.refColPack[] +function switch(method::String) + if method == "ROW_PARTIAL_DISTANCE_TWO" + return "COLUMN_PARTIAL_DISTANCE_TWO" + elseif method == "COLUMN_PARTIAL_DISTANCE_TWO" + return "ROW_PARTIAL_DISTANCE_TWO" + else + throw(ArgumentError("Invalid method")) + end +end function ColPackPartialColoring( - filename::AbstractString, - method::ColoringMethod, - order::ColoringOrder; - verbose::Bool=false, + filename::AbstractString, method::String, order::String; verbose::Bool=false ) + if !(method in PARTIAL_COLORING_METHODS) + throw(ArgumentError("""Method "$method" is not in $PARTIAL_COLORING_METHODS""")) + end + if !(order in PARTIAL_COLORING_ORDERS) + throw(ArgumentError("""Order "$order" is not in $PARTIAL_COLORING_ORDERS""")) + end refColPack = Ref{Ptr{Cvoid}}(C_NULL) reflen = Ref{Cint}(0) - ret = build_partial_coloring_from_file(refColPack, reflen, filename, method.method, order.order, verbose) + ret = build_partial_coloring_from_file( + refColPack, reflen, filename, method, order, verbose + ) (ret == 0) && error("ColPack partial coloring failed.") coloring = zeros(Cint, reflen[]) g = ColPackPartialColoring(refColPack, coloring, method, order) @@ -58,11 +90,14 @@ function ColPackPartialColoring( end function ColPackPartialColoring( - M::SparseMatrixCSC, - method::ColoringMethod, - order::ColoringOrder; - verbose::Bool=false, + M::SparseMatrixCSC, method::String, order::String; verbose::Bool=false ) + if !(method in PARTIAL_COLORING_METHODS) + throw(ArgumentError("""Method "$method" is not in $PARTIAL_COLORING_METHODS""")) + end + if !(order in PARTIAL_COLORING_ORDERS) + throw(ArgumentError("""Order "$order" is not in $PARTIAL_COLORING_ORDERS""")) + end reflen = Ref{Cint}(0) refColPack = Ref{Ptr{Cvoid}}(C_NULL) nrows, ncols = size(M) @@ -75,12 +110,12 @@ function ColPackPartialColoring( Mt_cols .-= Cint(1) Mt_rows .-= Cint(1) - (method.method == "ROW_PARTIAL_DISTANCE_TWO") && (colpack_method = "COLUMN_PARTIAL_DISTANCE_TWO") - (method.method == "COLUMN_PARTIAL_DISTANCE_TWO") && (colpack_method = "ROW_PARTIAL_DISTANCE_TWO") - ret = build_partial_coloring_from_csr(refColPack, reflen, Mt_rows, Mt_cols, ncols, nrows, colpack_method, order.order, verbose) + ret = build_partial_coloring_from_csr( + refColPack, reflen, Mt_rows, Mt_cols, ncols, nrows, switch(method), order, verbose + ) (ret == 0) && error("ColPack partial coloring failed.") coloring = zeros(Cint, reflen[]) - g = ColPackPartialColoring(refColPack, coloring, ColoringMethod(colpack_method), order) + g = ColPackPartialColoring(refColPack, coloring, switch(method), order) finalizer(free_partial_coloring, g) return g end diff --git a/src/libcolpack.jl b/src/libcolpack.jl index 300f33a..81ea9ad 100644 --- a/src/libcolpack.jl +++ b/src/libcolpack.jl @@ -1,36 +1,94 @@ function build_coloring_from_file(ref, len, _filename, _method, _order, verbose) - @ccall libcolpack.build_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, _filename::Ptr{Cchar}, - _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint + @ccall libcolpack.build_coloring_from_file( + ref::Ptr{Ptr{Cvoid}}, + len::Ptr{Cint}, + _filename::Ptr{Cchar}, + _method::Ptr{Cchar}, + _order::Ptr{Cchar}, + verbose::Cint, + )::Cint end function build_partial_coloring_from_file(ref, len, _filename, _method, _order, verbose) - @ccall libcolpack.build_partial_coloring_from_file(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, _filename::Ptr{Cchar}, - _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint + @ccall libcolpack.build_partial_coloring_from_file( + ref::Ptr{Ptr{Cvoid}}, + len::Ptr{Cint}, + _filename::Ptr{Cchar}, + _method::Ptr{Cchar}, + _order::Ptr{Cchar}, + verbose::Cint, + )::Cint end function build_bicoloring_from_file(ref, len1, len2, _filename, _method, _order, verbose) - @ccall libcolpack.build_bicoloring_from_file(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, _filename::Ptr{Cchar}, - _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint + @ccall libcolpack.build_bicoloring_from_file( + ref::Ptr{Ptr{Cvoid}}, + len1::Ptr{Cint}, + len2::Ptr{Cint}, + _filename::Ptr{Cchar}, + _method::Ptr{Cchar}, + _order::Ptr{Cchar}, + verbose::Cint, + )::Cint end function build_coloring_from_adolc(ref, len, adolc, rowcount, _method, _order, verbose) - @ccall libcolpack.build_coloring_from_adolc(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, adolc::Ptr{Ptr{Cuint}}, - rowcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint + @ccall libcolpack.build_coloring_from_adolc( + ref::Ptr{Ptr{Cvoid}}, + len::Ptr{Cint}, + adolc::Ptr{Ptr{Cuint}}, + rowcount::Cint, + _method::Ptr{Cchar}, + _order::Ptr{Cchar}, + verbose::Cint, + )::Cint end -function build_partial_coloring_from_adolc(ref, len, adolc, rowcount, colcount, _method, _order, verbose) - @ccall libcolpack.build_partial_coloring_from_adolc(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, adolc::Ptr{Ptr{Cuint}}, - rowcount::Cint, colcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint +function build_partial_coloring_from_adolc( + ref, len, adolc, rowcount, colcount, _method, _order, verbose +) + @ccall libcolpack.build_partial_coloring_from_adolc( + ref::Ptr{Ptr{Cvoid}}, + len::Ptr{Cint}, + adolc::Ptr{Ptr{Cuint}}, + rowcount::Cint, + colcount::Cint, + _method::Ptr{Cchar}, + _order::Ptr{Cchar}, + verbose::Cint, + )::Cint end -function build_bicoloring_from_adolc(ref, len1, len2, adolc, rowcount, colcount, _method, _order, verbose) - @ccall libcolpack.build_bicoloring_from_adolc(ref::Ptr{Ptr{Cvoid}}, len1::Ptr{Cint}, len2::Ptr{Cint}, adolc::Ptr{Ptr{Cuint}}, - rowcount::Cint, colcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint +function build_bicoloring_from_adolc( + ref, len1, len2, adolc, rowcount, colcount, _method, _order, verbose +) + @ccall libcolpack.build_bicoloring_from_adolc( + ref::Ptr{Ptr{Cvoid}}, + len1::Ptr{Cint}, + len2::Ptr{Cint}, + adolc::Ptr{Ptr{Cuint}}, + rowcount::Cint, + colcount::Cint, + _method::Ptr{Cchar}, + _order::Ptr{Cchar}, + verbose::Cint, + )::Cint end -function build_partial_coloring_from_csr(ref, len, rows, cols, rowcount, colcount, _method, _order, verbose) - @ccall libcolpack.build_partial_coloring_from_csr(ref::Ptr{Ptr{Cvoid}}, len::Ptr{Cint}, rows::Ptr{Cint}, cols::Ptr{Cint}, - rowcount::Cint, colcount::Cint, _method::Ptr{Cchar}, _order::Ptr{Cchar}, verbose::Cint)::Cint +function build_partial_coloring_from_csr( + ref, len, rows, cols, rowcount, colcount, _method, _order, verbose +) + @ccall libcolpack.build_partial_coloring_from_csr( + ref::Ptr{Ptr{Cvoid}}, + len::Ptr{Cint}, + rows::Ptr{Cint}, + cols::Ptr{Cint}, + rowcount::Cint, + colcount::Cint, + _method::Ptr{Cchar}, + _order::Ptr{Cchar}, + verbose::Cint, + )::Cint end function get_coloring(ref, coloring) @@ -42,7 +100,9 @@ function get_partial_coloring(ref, coloring) end function get_bicoloring(ref, left_coloring, right_coloring) - @ccall libcolpack.get_bicoloring(ref::Ptr{Cvoid}, left_coloring::Ptr{Cint}, right_coloring::Ptr{Cint})::Cvoid + @ccall libcolpack.get_bicoloring( + ref::Ptr{Cvoid}, left_coloring::Ptr{Cint}, right_coloring::Ptr{Cint} + )::Cvoid end function free_coloring(ref) diff --git a/src/method.jl b/src/method.jl deleted file mode 100644 index 08115a6..0000000 --- a/src/method.jl +++ /dev/null @@ -1,95 +0,0 @@ -""" - ColoringMethod - -Represent a [ColPack](https://github.com/CSCsw/ColPack)-compatible [coloring method](https://cscapes.cs.purdue.edu/coloringpage/software.htm#capabilities). - -# Fields - -- `method::String` - -# Constructors - -- [`d1_coloring()`](@ref) -- [`d2_coloring()`](@ref) -- [`acyclic_coloring()`](@ref) -- [`star_coloring()`](@ref) -- [`row_partial_d2_coloring()`](@ref) -- [`column_partial_d2_coloring()`](@ref) -- [`implicit_star_bicoloring()`](@ref) -- [`explicit_star_bicoloring()`](@ref) -- [`explicit_modified_star_bicoloring()`](@ref) -- [`implicit_greedy_star_bicoloring()`](@ref) -""" -struct ColoringMethod - method::String -end - -""" - d1_coloring() - -Shortcut for `ColoringMethod("DISTANCE_ONE")`. -""" -d1_coloring() = ColoringMethod("DISTANCE_ONE") - -""" - d2_coloring() - -Shortcut for `ColoringMethod("DISTANCE_TWO")`. -""" -d2_coloring() = ColoringMethod("DISTANCE_TWO") - -""" - acyclic_coloring() - -Shortcut for `ColoringMethod("ACYCLIC")`. -""" -acyclic_coloring() = ColoringMethod("ACYCLIC") - -""" - star_coloring() - -Shortcut for `ColoringMethod("STAR")`. -""" -star_coloring() = ColoringMethod("STAR") - -""" - row_partial_d2_coloring() - -Shortcut for `ColoringMethod("ROW_PARTIAL_DISTANCE_TWO")`. -""" -row_partial_d2_coloring() = ColoringMethod("ROW_PARTIAL_DISTANCE_TWO") - -""" - column_partial_d2_coloring() - -Shortcut for `ColoringMethod("COLUMN_PARTIAL_DISTANCE_TWO")`. -""" -column_partial_d2_coloring() = ColoringMethod("COLUMN_PARTIAL_DISTANCE_TWO") - -""" - implicit_star_bicoloring() - -Shortcut for `ColoringMethod("IMPLICIT_COVERING__STAR_BICOLORING")`. -""" -implicit_star_bicoloring() = ColoringMethod("IMPLICIT_COVERING__STAR_BICOLORING") - -""" - explicit_star_bicoloring() - -Shortcut for `ColoringMethod("EXPLICIT_COVERING__STAR_BICOLORING")`. -""" -explicit_star_bicoloring() = ColoringMethod("EXPLICIT_COVERING__STAR_BICOLORING") - -""" - explicit_modified_star_bicoloring() - -Shortcut for `ColoringMethod("EXPLICIT_COVERING__MODIFIED_STAR_BICOLORING")`. -""" -explicit_modified_star_bicoloring() = ColoringMethod("EXPLICIT_COVERING__MODIFIED_STAR_BICOLORING") - -""" - implicit_greedy_star_bicoloring() - -Shortcut for `ColoringMethod(IMPLICIT_COVERING__GREEDY_STAR_BICOLORING")`. -""" -implicit_greedy_star_bicoloring() = ColoringMethod("IMPLICIT_COVERING__GREEDY_STAR_BICOLORING") diff --git a/src/options.jl b/src/options.jl new file mode 100644 index 0000000..d167407 --- /dev/null +++ b/src/options.jl @@ -0,0 +1,63 @@ +#= +Sources: +- https://github.com/CSCsw/ColPack/tree/master/Examples +=# + +## Coloring on general graphs + +const COLORING_METHODS = [ + "DISTANCE_ONE", + "ACYCLIC", + "ACYCLIC_FOR_INDIRECT_RECOVERY", + "STAR", + "RESTRICTED_STAR", + "DISTANCE_TWO", +] + +const COLORING_ORDERS = [ + "NATURAL", + "RANDOM", + "LARGEST_FIRST", + "SMALLEST_LAST", + "DYNAMIC_LARGEST_FIRST", + "INCIDENCE_DEGREE", +] + +## Partial coloring on bipartite graphs + +const PARTIAL_COLORING_METHODS = [ + "COLUMN_PARTIAL_DISTANCE_TWO", # + "ROW_PARTIAL_DISTANCE_TWO", +] + +#= +Was DYNAMIC_LARGEST_FIRST forgotten in the source code? +https://github.com/CSCsw/ColPack/blob/9a7293a8dfd66a60434496b8df5ebb4274d70339/src/BipartiteGraphPartialColoring/BipartiteGraphPartialOrdering.cpp#L1859-L1938 +=# + +const PARTIAL_COLORING_ORDERS = [ + "NATURAL", + "RANDOM", + "LARGEST_FIRST", + # "DYNAMIC_LARGEST_FIRST", + "SMALLEST_LAST", + "INCIDENCE_DEGREE", +] + +## Bicoloring on bipartite graphs + +const BICOLORING_METHODS = [ + "IMPLICIT_COVERING__STAR_BICOLORING", + "EXPLICIT_COVERING__STAR_BICOLORING", + "EXPLICIT_COVERING__MODIFIED_STAR_BICOLORING", + "IMPLICIT_COVERING__GREEDY_STAR_BICOLORING", +] + +const BICOLORING_ORDERS = [ + "NATURAL", + "RANDOM", + "LARGEST_FIRST", + "DYNAMIC_LARGEST_FIRST", + "SMALLEST_LAST", + "INCIDENCE_DEGREE", +] diff --git a/src/order.jl b/src/order.jl deleted file mode 100644 index b59bdbe..0000000 --- a/src/order.jl +++ /dev/null @@ -1,87 +0,0 @@ -""" - ColoringOrder - -Represent a [ColPack](https://github.com/CSCsw/ColPack)-compatible [coloring order](https://cscapes.cs.purdue.edu/coloringpage/software.htm#Ordering). - -# Fields - -- `order::String` - -# Constructors - -- [`natural_ordering()`](@ref) -- [`largest_first_ordering()`](@ref) -- [`dynamic_largest_first_ordering()`](@ref) -- [`distance_two_largest_first_ordering()`](@ref) -- [`smallest_last_ordering()`](@ref) -- [`distance_two_smallest_last_ordering()`](@ref) -- [`incidence_degree_ordering()`](@ref) -- [`distance_two_incidence_degree_ordering()`](@ref) -- [`random_ordering()`](@ref) -""" -struct ColoringOrder - order::String -end - -""" - natural_ordering() - -Shortcut for `ColoringOrder("NATURAL")`. -""" -natural_ordering() = ColoringOrder("NATURAL") - -""" - largest_first_ordering() - -Shortcut for `ColoringOrder("LARGEST_FIRST")`. -""" -largest_first_ordering() = ColoringOrder("LARGEST_FIRST") - -""" - dynamic_largest_first_ordering() - -Shortcut for `ColoringOrder("DYNAMIC_LARGEST_FIRST")`. -""" -dynamic_largest_first_ordering() = ColoringOrder("DYNAMIC_LARGEST_FIRST") - -""" - distance_two_largest_first_ordering() - -Shortcut for `ColoringOrder("DISTANCE_TWO_LARGEST_FIRST")`. -""" -distance_two_largest_first_ordering() = ColoringOrder("DISTANCE_TWO_LARGEST_FIRST") - -""" - smallest_last_ordering() - -Shortcut for `ColoringOrder("SMALLEST_LAST")`. -""" -smallest_last_ordering() = ColoringOrder("SMALLEST_LAST") - -""" - distance_two_smallest_last_ordering() - -Shortcut for `ColoringOrder("DISTANCE_TWO_SMALLEST_LAST")`. -""" -distance_two_smallest_last_ordering() = ColoringOrder("DISTANCE_TWO_SMALLEST_LAST") - -""" - incidence_degree_ordering() - -Shortcut for `ColoringOrder("INCIDENCE_DEGREE")`. -""" -incidence_degree_ordering() = ColoringOrder("INCIDENCE_DEGREE") - -""" - distance_two_incidence_degree_ordering() - -Shortcut for `ColoringOrder("DISTANCE_TWO_INCIDENCE_DEGREE")`. -""" -distance_two_incidence_degree_ordering() = ColoringOrder("DISTANCE_TWO_INCIDENCE_DEGREE") - -""" - random_ordering() - -Shortcut for `ColoringOrder("RANDOM")`. -""" -random_ordering() = ColoringOrder("RANDOM") diff --git a/src/utils.jl b/src/utils.jl deleted file mode 100644 index b933cee..0000000 --- a/src/utils.jl +++ /dev/null @@ -1,61 +0,0 @@ -""" - _cols_by_rows(rows_index, cols_index) - -Returns a vector of rows where each row contains -a vector of its column indices. -""" -function _cols_by_rows(rows_index,cols_index) - nrows = maximum(rows_index) - cols_by_rows = [eltype(rows_index)[] for _ in 1:nrows] - for (i,j) in zip(rows_index,cols_index) - push!(cols_by_rows[i],j) - end - return cols_by_rows -end - -""" - _rows_by_cols(rows_index, cols_index) - -Returns a vector of columns where each column contains -a vector of its row indices. -""" -function _rows_by_cols(rows_index,cols_index) - return _cols_by_rows(cols_index,rows_index) -end - -""" - matrix2adjmatrix(M::AbstractMatrix; partition_by_rows=true) - -Create an adjacency matrix between the rows or between the columns of `M`, depending on whether `partition_by_rows` is `true` or `false`. -""" -function matrix2adjmatrix(M::AbstractMatrix; partition_by_rows = true) - (rows_index, cols_index, _) = findnz(M) - if partition_by_rows - A = SparseMatrixCSC{Float64, Cuint}(size(M,1), size(M,1), ones(Cuint, size(M,1)+1), Vector{Cuint}(), Vector{Float64}()) - rows_by_cols = _rows_by_cols(rows_index,cols_index) - @inbounds for (cur_row,cur_col) in zip(rows_index,cols_index) - if !isempty(rows_by_cols[cur_col]) - for next_row in rows_by_cols[cur_col] - if next_row < cur_row - A[cur_row, next_row] = 1.0 - A[next_row, cur_row] = 1.0 - end - end - end - end - else - A = SparseMatrixCSC{Float64, Cuint}(size(M,2), size(M,2), ones(Cuint, size(M,2)+1), Vector{Cuint}(), Vector{Float64}()) - cols_by_rows = _cols_by_rows(rows_index,cols_index) - @inbounds for (cur_row,cur_col) in zip(rows_index,cols_index) - if !isempty(cols_by_rows[cur_row]) - for next_col in cols_by_rows[cur_row] - if next_col < cur_col - A[cur_col, next_col] = 1.0 - A[next_col, cur_col] = 1.0 - end - end - end - end - end - return A -end diff --git a/test/Project.toml b/test/Project.toml index 02cb6af..2a7be4d 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -6,6 +6,5 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MatrixMarket = "4d4711f2-db25-561a-b6b3-d35e7d4047d3" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/coloring.jl b/test/coloring.jl new file mode 100644 index 0000000..8be62c1 --- /dev/null +++ b/test/coloring.jl @@ -0,0 +1,106 @@ +using ColPack +using ColPack: COLORING_METHODS, PARTIAL_COLORING_METHODS, BICOLORING_METHODS +using ColPack: COLORING_ORDERS, PARTIAL_COLORING_ORDERS, BICOLORING_ORDERS +using LinearAlgebra +using MatrixMarket +using Random +using SparseArrays +using StableRNGs +using Test + +rng = StableRNG(63) + +asymmetric_params = vcat( + [(10, 20, p) for p in (0.0:0.1:1.0)], # + [(20, 10, p) for p in (0.0:0.1:1.0)], + [(100, 200, p) for p in (0.01:0.01:0.05)], # + [(200, 100, p) for p in (0.01:0.01:0.05)], +) + +symmetric_params = vcat( + [(10, p) for p in (0.0:0.1:1.0)], # + [(100, p) for p in (0.01:0.01:0.05)], +) + +function test_colors(A::AbstractMatrix, method::String, colors::AbstractVector{<:Integer}) + @test minimum(colors) >= 1 + if occursin("COLUMN", method) + @test length(colors) == size(A, 2) + @test maximum(colors) <= size(A, 2) + elseif occursin("ROW", method) + @test length(colors) == size(A, 1) + @test maximum(colors) <= size(A, 1) + else + @test issymmetric(A) + @test maximum(colors) <= size(A, 1) + end +end + +function test_colors( + A::AbstractMatrix, + method::String, + colors1::AbstractVector{<:Integer}, + colors2::AbstractVector{<:Integer}, +) + #= + I don't know yet what the indices of colors1 and colors2 mean (especially the extremal ones). + This makes it hard to test it properly. + =# + @test length(colors1) <= size(A, 1) + @test maximum(colors1) <= size(A, 1) + @test length(colors2) <= size(A, 2) + @test isempty(intersect(Set(colors1), Set(colors2))) +end + +@testset verbose = true "General graph coloring" begin + @testset "$method" for method in COLORING_METHODS + @testset "$order" for order in COLORING_ORDERS + @testset "(n, p) = $((n, p))" for (n, p) in symmetric_params + H = sparse(Symmetric(sprand(rng, Bool, n, n, p))) + filename = joinpath(@__DIR__, "H.mtx") + MatrixMarket.mmwrite(filename, H) + coloring_mat = ColPackColoring(H, method, order; verbose=false) + coloring_file = ColPackColoring(filename, method, order; verbose=false) + @test get_colors(coloring_mat) == get_colors(coloring_file) + colors = get_colors(coloring_file) + test_colors(H, method, colors) + end + end + end +end; + +@testset verbose = true "Bipartite graph partial coloring" begin + @testset "$method" for method in PARTIAL_COLORING_METHODS + @testset "$order" for order in PARTIAL_COLORING_ORDERS[1:1] + @testset "(n, m, p) = $((n, m, p))" for (n, m, p) in asymmetric_params + J = sprand(rng, Bool, n, m, p) + filename = joinpath(@__DIR__, "J.mtx") + MatrixMarket.mmwrite(filename, J) + coloring_mat = ColPackPartialColoring(J, method, order; verbose=false) + coloring_file = ColPackPartialColoring( + filename, method, order; verbose=false + ) + @test length(get_colors(coloring_mat)) == length(get_colors(coloring_file)) + # this is not always true since we use different algorithms + # @test get_colors(coloring_mat) == get_colors(coloring_file) + test_colors(J, method, get_colors(coloring_mat)) + test_colors(J, method, get_colors(coloring_file)) + end + end + end +end; + +@testset verbose = true "Bipartite graph bicoloring" begin + @testset "$method" for method in BICOLORING_METHODS + @testset "$order" for order in BICOLORING_ORDERS[1:1] + @testset "(n, m, p) = $((n, m, p))" for (n, m, p) in asymmetric_params + J = sprand(rng, Bool, n, m, p) + filename = joinpath(@__DIR__, "J.mtx") + MatrixMarket.mmwrite(filename, J) + coloring_file = ColPackBiColoring(filename, method, order; verbose=false) + colors1, colors2 = get_colors(coloring_file) + test_colors(J, method, colors1, colors2) + end + end + end +end; diff --git a/test/exceptions.jl b/test/exceptions.jl new file mode 100644 index 0000000..1c56a76 --- /dev/null +++ b/test/exceptions.jl @@ -0,0 +1,43 @@ +using ColPack +using SparseArrays +using Test + +J_dense = [1 0 1; 0 1 0] +H_dense = [1 0; 0 1] +J = sparse(J_dense) +H = sparse(H_dense) + +## No errors in normal case + +@test get_colors(ColPackColoring(H, "STAR", "NATURAL")) isa Vector{Int32} +@test get_colors(ColPackPartialColoring(J, "COLUMN_PARTIAL_DISTANCE_TWO", "NATURAL")) isa + Vector{Int32} +@test_broken get_colors( + ColPackBiColoring(J, "EXPLICIT_COVERING__STAR_BICOLORING", "NATURAL") +) isa NTuple{Vector{Int32},2} + +## Error on dense matrix + +@test_throws MethodError ColPackColoring(H_dense, "STAR", "NATURAL") +@test_throws MethodError ColPackPartialColoring( + J_dense, "COLUMN_PARTIAL_DISTANCE_TWO", "NATURAL" +) +@test_throws MethodError ColPackBiColoring( + J_dense, "EXPLICIT_COVERING__STAR_BICOLORING", "NATURAL" +) + +## Error on non-existent method + +@test_throws ArgumentError ColPackColoring(H, "STARDEW_VALLEY", "NATURAL") +@test_throws ArgumentError ColPackPartialColoring(J, "NEWSPAPER_COLUMNIST", "NATURAL") + +## Error on non-existent order + +@test_throws ArgumentError ColPackColoring(H, "STAR", "UNNATURAL") +@test_throws ArgumentError ColPackPartialColoring( + J, "COLUMN_PARTIAL_DISTANCE_TWO", "SUPERNATURAL" +) + +## Error on non-square + +@test_throws DimensionMismatch ColPackColoring(J, "STAR", "NATURAL") diff --git a/test/functionality.jl b/test/functionality.jl deleted file mode 100644 index 696acf3..0000000 --- a/test/functionality.jl +++ /dev/null @@ -1,84 +0,0 @@ -using ColPack -using LinearAlgebra -using MatrixMarket -using Random -using SparseArrays -using SparseDiffTools -using StableRNGs -using Test - -rng = StableRNG(63) - -orderings = Vector{ColoringOrder}() - -push!(orderings, natural_ordering()) -push!(orderings, largest_first_ordering()) -push!(orderings, dynamic_largest_first_ordering()) -push!(orderings, distance_two_largest_first_ordering()) -push!(orderings, smallest_last_ordering()) -push!(orderings, distance_two_smallest_last_ordering()) -push!(orderings, incidence_degree_ordering()) -push!(orderings, distance_two_incidence_degree_ordering()) -# push!(orderings, random_ordering()) - -ncolors = Vector{Cint}() - -push!(ncolors, 7) -push!(ncolors, 7) -push!(ncolors, 6) -push!(ncolors, 7) # changed -push!(ncolors, 6) -push!(ncolors, 6) -push!(ncolors, 6) # changed -push!(ncolors, 6) -# push!(ncolors, 10) - -Random.seed!(2713) -# Create adjacency graph -# TODO: random is a bad idea, nb of colors may change (temporarily fixed with StableRNGs) -A = convert(SparseMatrixCSC, Symmetric(sprand(rng, 100, 100, 0.1))) - -const filename = joinpath(@__DIR__, "A.mtx") -MatrixMarket.mmwrite(filename, A) -verbose = false - -@testset "MatrixMarket API" begin - @testset "Coloring -- $ordering" for (i, ordering) in enumerate(orderings) - coloring = ColPackColoring(filename, d1_coloring(), ordering; verbose=verbose) - @test maximum(get_colors(coloring)) == ncolors[i] - end - - @testset "Partial coloring -- $ordering" for (i, ordering) in enumerate(orderings) - row_coloring = ColPackPartialColoring(filename, row_partial_d2_coloring(), ordering; verbose=verbose) - column_coloring = ColPackPartialColoring(filename, column_partial_d2_coloring(), ordering; verbose=verbose) - end -end - -@testset "ADOL-C Compressed Row Storage" begin - @testset "Coloring -- $ordering" for (i, ordering) in enumerate(orderings) - coloring = ColPackColoring(A, d1_coloring(), ordering; verbose=verbose) - @test maximum(get_colors(coloring)) == ncolors[i] - end -end - -@testset "CSR Storage" begin - @testset "Partial coloring -- $ordering" for (i, ordering) in enumerate(orderings) - row_coloring = ColPackPartialColoring(A, row_partial_d2_coloring(), ordering; verbose=verbose) - column_coloring = ColPackPartialColoring(A, column_partial_d2_coloring(), ordering; verbose=verbose) - end -end - -@testset "ColPack Columns Coloring" begin - A = [ - [1.0 1.0 0.0 0.0 0.0] - [0.0 0.0 1.0 0.0 0.0] - [0.0 1.0 0.0 1.0 0.0] - [0.0 0.0 0.0 1.0 1.0] - ] - - A = sparse(A) - adjA = ColPack.matrix2adjmatrix(A; partition_by_rows=false) - @test issymmetric(adjA) - coloring = ColPackColoring(adjA, d1_coloring(), natural_ordering(); verbose=true) - @test get_colors(coloring) == SparseDiffTools.matrix_colors(A) -end diff --git a/test/runtests.jl b/test/runtests.jl index 9298925..8082efa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -16,7 +16,10 @@ using Test @testset "Doctests" begin Documenter.doctest(ColPack) end - @testset verbose = true "Functionality" begin - include("functionality.jl") + @testset verbose = true "Coloring" begin + include("coloring.jl") + end + @testset verbose = true "Exceptions" begin + include("exceptions.jl") end end From 800b1336188b5d16a36148ead342bb00fbb4d0e1 Mon Sep 17 00:00:00 2001 From: Guillaume Dalle <22795598+gdalle@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:16:47 +0200 Subject: [PATCH 4/5] Dont export bicoloring --- src/ColPack.jl | 2 +- src/colpack_bicoloring.jl | 15 +++++++++------ test/coloring.jl | 2 +- test/exceptions.jl | 1 + 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ColPack.jl b/src/ColPack.jl index fcf0d57..3f003f5 100644 --- a/src/ColPack.jl +++ b/src/ColPack.jl @@ -28,6 +28,6 @@ include("colpack_bicoloring.jl") # Exports -export ColPackColoring, ColPackPartialColoring, ColPackBiColoring, get_colors +export ColPackColoring, ColPackPartialColoring, get_colors end #module diff --git a/src/colpack_bicoloring.jl b/src/colpack_bicoloring.jl index fe80eff..4426d8a 100644 --- a/src/colpack_bicoloring.jl +++ b/src/colpack_bicoloring.jl @@ -3,13 +3,16 @@ Struct holding the parameters of a bicoloring as well as its results (which can be queried with [`get_colors`](@ref)). +!!! danger + This is still experimental and not protected by semantic versioning, use at your own risk. + # Constructors -ColPackBiColoring( - filename::AbstractString, - method::String, - order::String; - verbose::Bool=false + ColPackBiColoring( + filename::AbstractString, + method::String, + order::String; + verbose::Bool=false ) ColPackBiColoring( @@ -66,7 +69,7 @@ end """ get_colors(coloring::ColPackBiColoring) -Retrieve the colors from a [`ColPackBiColoring`](@ref) as two vectors of integers. +Retrieve the colors from a [`ColPackBiColoring`](@ref) as two vectors of integers, one for the rows and one for the columns respectively. """ function get_colors(coloring::ColPackBiColoring) get_bicoloring(coloring.refColPack[], coloring.coloring1, coloring.coloring2) diff --git a/test/coloring.jl b/test/coloring.jl index 8be62c1..b7bc4be 100644 --- a/test/coloring.jl +++ b/test/coloring.jl @@ -1,4 +1,5 @@ using ColPack +using ColPack: ColPackBiColoring using ColPack: COLORING_METHODS, PARTIAL_COLORING_METHODS, BICOLORING_METHODS using ColPack: COLORING_ORDERS, PARTIAL_COLORING_ORDERS, BICOLORING_ORDERS using LinearAlgebra @@ -47,7 +48,6 @@ function test_colors( This makes it hard to test it properly. =# @test length(colors1) <= size(A, 1) - @test maximum(colors1) <= size(A, 1) @test length(colors2) <= size(A, 2) @test isempty(intersect(Set(colors1), Set(colors2))) end diff --git a/test/exceptions.jl b/test/exceptions.jl index 1c56a76..abe53f9 100644 --- a/test/exceptions.jl +++ b/test/exceptions.jl @@ -1,4 +1,5 @@ using ColPack +using ColPack: ColPackBiColoring using SparseArrays using Test From c6c7173b451d6819864f6699dc6e61a36a3361c9 Mon Sep 17 00:00:00 2001 From: Guillaume Dalle <22795598+gdalle@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:26:41 +0200 Subject: [PATCH 5/5] Add transposition warning --- src/colpack_partial_coloring.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/colpack_partial_coloring.jl b/src/colpack_partial_coloring.jl index 9c90632..03f5b4f 100644 --- a/src/colpack_partial_coloring.jl +++ b/src/colpack_partial_coloring.jl @@ -26,6 +26,9 @@ The users needs to specify: - a partial coloring `method` among `$PARTIAL_COLORING_METHODS` - an `order` on the vertices among `$PARTIAL_COLORING_ORDERS` +!!! warning + To perform a partial column coloring of a CSC matrix, we actually perform a partial row coloring of its transpose (which is a CSR matrix). Thus, the coloring results will in general differ between the file API and the matrix API. + # Example ```jldoctest