Skip to content
3 changes: 3 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[weakdeps]
CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"

[extensions]
SparseMatrixColoringsCliqueTreesExt = "CliqueTrees"
SparseMatrixColoringsColorsExt = "Colors"

[compat]
ADTypes = "1.2.1"
CliqueTrees = "0.5.2"
Colors = "0.12.11, 0.13"
DataStructures = "0.18"
DocStringExtensions = "0.8,0.9"
Expand Down
3 changes: 3 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"

[sources]
SparseMatrixColorings = {path=".."}
1 change: 1 addition & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ SmallestLast
IncidenceDegree
DynamicLargestFirst
DynamicDegreeBasedOrder
PerfectEliminationOrder
```
24 changes: 24 additions & 0 deletions ext/SparseMatrixColoringsCliqueTreesExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module SparseMatrixColoringsCliqueTreesExt

import CliqueTrees: permutation, LexBFS, MCS
import SparseArrays: SparseMatrixCSC, rowvals, nnz
import SparseMatrixColorings:
AdjacencyGraph, BipartiteGraph, PerfectEliminationOrder, pattern, vertices

function vertices(g::AdjacencyGraph{T}, order::PerfectEliminationOrder) where {T}
S = pattern(g)
Comment thread
samuelsonric marked this conversation as resolved.
Outdated

# construct matrix with sparsity pattern S
M = SparseMatrixCSC{Bool,T}(size(S)..., S.colptr, rowvals(S), ones(Bool, nnz(S)))

# construct a perfect elimination order
# self-loops are ignored
# we can also use alg=LexBFS()
Comment thread
gdalle marked this conversation as resolved.
Outdated
# - time complexity: O(|V| + |E|)
# - space complexity: O(|V| + |E|)
order, _ = permutation(M; alg=MCS())

return reverse!(order)
end

end # module
1 change: 1 addition & 0 deletions src/SparseMatrixColorings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ include("show_colors.jl")

export NaturalOrder, RandomOrder, LargestFirst
export DynamicDegreeBasedOrder, SmallestLast, IncidenceDegree, DynamicLargestFirst
export PerfectEliminationOrder
export ColoringProblem, GreedyColoringAlgorithm, AbstractColoringResult
export ConstantColoringAlgorithm
export coloring, fast_coloring
Expand Down
14 changes: 14 additions & 0 deletions src/order.jl
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,17 @@ Instance of [`AbstractOrder`](@ref) which sorts vertices from lowest to highest
- [`DynamicDegreeBasedOrder`](@ref)
"""
const DynamicLargestFirst = DynamicDegreeBasedOrder{:forward,:low2high}

"""
PerfectEliminationOrder

A linear-time ordering code for symmetric graphs. On [chordal graphs](https://en.wikipedia.org/wiki/Chordal_graph), the code computes a perfect elimination ordering. Otherwise, it computes a suboptimal ordering.
Comment thread
gdalle marked this conversation as resolved.
Outdated

!!! danger
This order is implemented as a package extension and requires loading [CliqueTrees.jl](https://github.com/AlgebraicJulia/CliqueTrees.jl).

# References

- [Simple Linear-Time Algorithms to Test Chordality of Graphs, Test Acyclicity of Hypergraphs, and Selectively Reduce Acyclic Hypergraphs](https://epubs.siam.org/doi/10.1137/0213035), Tarjan and Yannakakis (1984)
"""
struct PerfectEliminationOrder <: AbstractOrder end
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
Chairmarks = "0ca39b1e-fe0b-4e98-acfc-b1656634c4de"
CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Expand Down
26 changes: 26 additions & 0 deletions test/order.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using CliqueTrees: CliqueTrees
using BandedMatrices
using LinearAlgebra
using SparseArrays
using SparseMatrixColorings
Expand All @@ -7,6 +9,7 @@ using SparseMatrixColorings:
LargestFirst,
NaturalOrder,
RandomOrder,
PerfectEliminationOrder,
degree_dist2,
nb_vertices,
valid_dynamic_order,
Expand Down Expand Up @@ -110,3 +113,26 @@ end;
end
end
end;

@testset "PerfectEliminationOrder" begin
problem = ColoringProblem(; structure=:symmetric, partition=:column)
algorithm = GreedyColoringAlgorithm(
PerfectEliminationOrder(); decompression=:substitution
)

# band graphs
for (n, m) in ((800, 80), (400, 40), (200, 20), (100, 10))
perm = randperm(rng, n)
matrix = permute!(sparse(Symmetric(brand(n, n, m, 0), :L)), perm, perm)
Comment thread
samuelsonric marked this conversation as resolved.
π = vertices(AdjacencyGraph(matrix), PerfectEliminationOrder())
@test isperm(π)
@test ncolors(coloring(matrix, problem, algorithm)) == m + 1
end

# random graphs
for (n, p) in Iterators.product(20:20:100, 0.0:0.1:0.2)
matrix = sparse(Symmetric(sprand(rng, Bool, n, n, p)))
π = vertices(AdjacencyGraph(matrix), PerfectEliminationOrder())
@test isperm(π)
end
end