Skip to content

Commit c6a0c99

Browse files
committed
Implement our own structure Forest
1 parent d854aa4 commit c6a0c99

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.13"
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"
@@ -20,7 +19,6 @@ SparseMatrixColoringsColorsExt = "Colors"
2019
[compat]
2120
ADTypes = "1.2.1"
2221
Colors = "0.12.11, 0.13"
23-
DataStructures = "0.18"
2422
DocStringExtensions = "0.8,0.9"
2523
LinearAlgebra = "<0.0.1, 1"
2624
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
@@ -301,11 +301,7 @@ function acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessin
301301
forbidden_colors = zeros(Int, nv)
302302
first_neighbor = fill((0, 0), nv) # at first no neighbors have been encountered
303303
first_visit_to_tree = fill((0, 0), ne)
304-
forest = DisjointSets{Tuple{Int,Int}}()
305-
sizehint!(forest.intmap, ne)
306-
sizehint!(forest.revmap, ne)
307-
sizehint!(forest.internal.parents, ne)
308-
sizehint!(forest.internal.ranks, ne)
304+
forest = Forest{Int}(ne)
309305
vertices_in_order = vertices(g, order)
310306

311307
for v in vertices_in_order
@@ -346,7 +342,7 @@ function acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessin
346342
end
347343

348344
# compress forest
349-
for edge in forest.revmap
345+
for edge in keys(forest.intmap)
350346
find_root!(forest, edge)
351347
end
352348
tree_set = TreeSet(forest, nb_vertices(g))
@@ -365,11 +361,10 @@ function _prevent_cycle!(
365361
# modified
366362
first_visit_to_tree::AbstractVector{<:Tuple},
367363
forbidden_colors::AbstractVector{<:Integer},
368-
forest::DisjointSets{<:Tuple{Int,Int}},
364+
forest::Forest{<:Integer},
369365
)
370366
wx = _sort(w, x)
371-
root = find_root!(forest, wx) # edge wx belongs to the 2-colored tree T represented by edge "root"
372-
id = forest.intmap[root] # ID of the representative edge "root" of a two-colored tree T.
367+
id = find_root!(forest, wx) # The edge wx belongs to the 2-colored tree T, represented by an edge with an integer ID
373368
(p, q) = first_visit_to_tree[id]
374369
if p != v # T is being visited from vertex v for the first time
375370
vw = _sort(v, w)
@@ -387,7 +382,7 @@ function _grow_star!(
387382
color::AbstractVector{<:Integer},
388383
# modified
389384
first_neighbor::AbstractVector{<:Tuple},
390-
forest::DisjointSets{Tuple{Int,Int}},
385+
forest::Forest{<:Integer},
391386
)
392387
vw = _sort(v, w)
393388
push!(forest, vw) # Create a new tree T_{vw} consisting only of edge vw
@@ -410,7 +405,7 @@ function _merge_trees!(
410405
w::Integer,
411406
x::Integer,
412407
# modified
413-
forest::DisjointSets{Tuple{Int,Int}},
408+
forest::Forest{<:Integer},
414409
)
415410
vw = _sort(v, w)
416411
wx = _sort(w, x)
@@ -436,12 +431,11 @@ struct TreeSet
436431
reverse_bfs_orders::Vector{Vector{Tuple{Int,Int}}}
437432
end
438433

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

446440
# dictionary that maps a tree's root to the index of the tree
447441
roots = Dict{Int,Int}()
@@ -451,12 +445,10 @@ function TreeSet(forest::DisjointSets{Tuple{Int,Int}}, nvertices::Int)
451445

452446
# counter of the number of roots found
453447
k = 0
454-
for edge in forest.revmap
448+
for edge in keys(forest.intmap)
455449
i, j = edge
456450
# forest has already been compressed so this doesn't change its state
457-
# I wanted to use find_root but it is deprecated
458-
root_edge = find_root!(forest, edge)
459-
root = forest.intmap[root_edge]
451+
root = find_root!(forest, edge)
460452

461453
# Update roots
462454
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)