Skip to content

Commit f6dc1a6

Browse files
committed
Implement our own structure Forest
1 parent a113eea commit f6dc1a6

4 files changed

Lines changed: 65 additions & 23 deletions

File tree

Project.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ version = "0.4.15"
55

66
[deps]
77
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
8-
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
98
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
109
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1110
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
@@ -23,7 +22,6 @@ SparseMatrixColoringsColorsExt = "Colors"
2322
ADTypes = "1.2.1"
2423
CliqueTrees = "0.5.2"
2524
Colors = "0.12.11, 0.13"
26-
DataStructures = "0.18"
2725
DocStringExtensions = "0.8,0.9"
2826
LinearAlgebra = "<0.0.1, 1"
2927
Random = "<0.0.1, 1"

src/SparseMatrixColorings.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ module SparseMatrixColorings
1111

1212
using ADTypes: ADTypes
1313
using Base.Iterators: Iterators
14-
using DataStructures: DisjointSets, find_root!, root_union!, num_groups
1514
using DocStringExtensions: README, EXPORTS, SIGNATURES, TYPEDEF, TYPEDFIELDS
1615
using LinearAlgebra:
1716
Adjoint,
@@ -43,6 +42,7 @@ using SparseArrays:
4342
spzeros
4443

4544
include("graph.jl")
45+
include("forest.jl")
4646
include("order.jl")
4747
include("coloring.jl")
4848
include("result.jl")

src/coloring.jl

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,7 @@ function acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessin
302302
forbidden_colors = zeros(Int, nv)
303303
first_neighbor = fill((0, 0), nv) # at first no neighbors have been encountered
304304
first_visit_to_tree = fill((0, 0), ne)
305-
forest = DisjointSets{Tuple{Int,Int}}()
306-
sizehint!(forest.intmap, ne)
307-
sizehint!(forest.revmap, ne)
308-
sizehint!(forest.internal.parents, ne)
309-
sizehint!(forest.internal.ranks, ne)
305+
forest = Forest{Int}(ne)
310306
vertices_in_order = vertices(g, order)
311307

312308
for v in vertices_in_order
@@ -347,7 +343,7 @@ function acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessin
347343
end
348344

349345
# compress forest
350-
for edge in forest.revmap
346+
for edge in keys(forest.intmap)
351347
find_root!(forest, edge)
352348
end
353349
tree_set = TreeSet(forest, nb_vertices(g))
@@ -367,11 +363,10 @@ function _prevent_cycle!(
367363
# modified
368364
first_visit_to_tree::AbstractVector{<:Tuple},
369365
forbidden_colors::AbstractVector{<:Integer},
370-
forest::DisjointSets{<:Tuple{Int,Int}},
366+
forest::Forest{<:Integer},
371367
)
372368
wx = _sort(w, x)
373-
root = find_root!(forest, wx) # edge wx belongs to the 2-colored tree T represented by edge "root"
374-
id = forest.intmap[root] # ID of the representative edge "root" of a two-colored tree T.
369+
id = find_root!(forest, wx) # The edge wx belongs to the 2-colored tree T, represented by an edge with an integer ID
375370
(p, q) = first_visit_to_tree[id]
376371
if p != v # T is being visited from vertex v for the first time
377372
vw = _sort(v, w)
@@ -389,7 +384,7 @@ function _grow_star!(
389384
color::AbstractVector{<:Integer},
390385
# modified
391386
first_neighbor::AbstractVector{<:Tuple},
392-
forest::DisjointSets{Tuple{Int,Int}},
387+
forest::Forest{<:Integer},
393388
)
394389
vw = _sort(v, w)
395390
push!(forest, vw) # Create a new tree T_{vw} consisting only of edge vw
@@ -412,7 +407,7 @@ function _merge_trees!(
412407
w::Integer,
413408
x::Integer,
414409
# modified
415-
forest::DisjointSets{Tuple{Int,Int}},
410+
forest::Forest{<:Integer},
416411
)
417412
vw = _sort(v, w)
418413
wx = _sort(w, x)
@@ -438,12 +433,11 @@ struct TreeSet
438433
is_star::Vector{Bool}
439434
end
440435

441-
function TreeSet(forest::DisjointSets{Tuple{Int,Int}}, nvertices::Int)
442-
# forest is a structure DisjointSets from DataStructures.jl
436+
function TreeSet(forest::Forest{Int}, nvertices::Int)
437+
# Forest is a structure defined in forest.jl
443438
# - forest.intmap: a dictionary that maps an edge (i, j) to an integer k
444-
# - forest.revmap: a dictionary that does the reverse of intmap, mapping an integer k to an edge (i, j)
445-
# - forest.internal.ngroups: the number of trees in the forest
446-
ntrees = forest.internal.ngroups
439+
# - forest.ntrees: the number of trees in the forest
440+
ntrees = forest.ntrees
447441

448442
# dictionary that maps a tree's root to the index of the tree
449443
roots = Dict{Int,Int}()
@@ -454,11 +448,9 @@ function TreeSet(forest::DisjointSets{Tuple{Int,Int}}, nvertices::Int)
454448

455449
# counter of the number of roots found
456450
k = 0
457-
for edge in forest.revmap
451+
for edge in keys(forest.intmap)
458452
i, j = edge
459-
# forest has already been compressed so this doesn't change its state
460-
root_edge = find_root!(forest, edge)
461-
root = forest.intmap[root_edge]
453+
root = find_root!(forest, edge)
462454

463455
# Update roots
464456
if !haskey(roots, root)

src/forest.jl

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
mutable struct Forest{T<:Integer}
2+
counter::T
3+
intmap::Dict{Tuple{T,T},T}
4+
parents::Vector{T}
5+
ranks::Vector{T}
6+
ntrees::T
7+
end
8+
9+
function Forest{T}(n::Integer) where {T<:Integer}
10+
counter = zero(T)
11+
intmap = Dict{Tuple{T,T},T}()
12+
sizehint!(intmap, n)
13+
parents = collect(Base.OneTo(T(n)))
14+
ranks = zeros(T, T(n))
15+
ntrees = T(n)
16+
return Forest{T}(counter, intmap, parents, ranks, ntrees)
17+
end
18+
19+
function Base.push!(forest::Forest{T}, edge::Tuple{T,T}) where {T<:Integer}
20+
forest.counter += 1
21+
forest.intmap[edge] = forest.counter
22+
forest.ntrees += one(T)
23+
return edge
24+
end
25+
26+
function _find_root!(parents::Vector{T}, index_edge::T) where {T<:Integer}
27+
@inbounds p = parents[index_edge]
28+
@inbounds if parents[p] != p
29+
parents[index_edge] = p = _find_root!(parents, p)
30+
end
31+
return p
32+
end
33+
34+
function find_root!(forest::Forest{T}, edge::Tuple{T,T}) where {T<:Integer}
35+
return _find_root!(forest.parents, forest.intmap[edge])
36+
end
37+
38+
function root_union!(forest::Forest{T}, index_edge1::T, index_edge2::T) where {T<:Integer}
39+
parents = forest.parents
40+
rks = forest.ranks
41+
@inbounds rank1 = rks[index_edge1]
42+
@inbounds rank2 = rks[index_edge2]
43+
44+
if rank1 < rank2
45+
index_edge1, index_edge2 = index_edge2, index_edge1
46+
elseif rank1 == rank2
47+
rks[index_edge1] += one(T)
48+
end
49+
@inbounds parents[index_edge2] = index_edge1
50+
forest.ntrees -= one(T)
51+
return nothing
52+
end

0 commit comments

Comments
 (0)