@@ -83,14 +83,12 @@ function star_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessing::
8383 ne = nb_edges (g)
8484 color = zeros (Int, nv)
8585 forbidden_colors = zeros (Int, nv)
86+ edge_to_index = Vector {Int} (undef, nnz (S))
8687 first_neighbor = fill ((0 , 0 , 0 ), nv) # at first no neighbors have been encountered
8788 treated = zeros (Int, nv)
88- edge_to_index = Vector {Int} (undef, nnz (S))
8989 star = Vector {Int} (undef, ne)
9090 hub = Int[] # one hub for each star, including the trivial ones
91- sizehint! (hub, ne)
9291 nb_spokes = Int[] # number of spokes for each star
93- sizehint! (nb_spokes, ne)
9492 vertices_in_order = vertices (g, order)
9593
9694 # edge_to_index gives an index for each edge
@@ -130,7 +128,7 @@ function star_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessing::
130128 else
131129 first_neighbor[color[w]] = (v, w, index_vw)
132130 for (ix, x) in enumerate (neighbors2 (g, w))
133- (x == w || x == v || iszero (color[x])) && continue
131+ (w == x || x == v || iszero (color[x])) && continue
134132 index_wx = edge_to_index[S. colptr[w] + ix - 1 ]
135133 if x == hub[star[index_wx]] # potential Case 2 (which is always false for trivial stars with two vertices, since the associated hub is negative)
136134 forbidden_colors[color[x]] = v
@@ -190,7 +188,7 @@ function _update_stars!(
190188 index_vw = edge_to_index[S. colptr[v] + iw - 1 ]
191189 x_exists = false
192190 for (ix, x) in enumerate (neighbors2 (g, w))
193- (x == w ) && continue
191+ (w == x ) && continue
194192 if x != v && color[x] == color[v] # vw, wx ∈ E
195193 index_wx = edge_to_index[S. colptr[w] + ix - 1 ]
196194 star_wx = star[index_wx]
@@ -278,8 +276,6 @@ function StarSet(
278276 return StarSet (star, hub, spokes)
279277end
280278
281- _sort (u, v) = (min (u, v), max (u, v))
282-
283279"""
284280 acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessing::Bool)
285281
@@ -305,27 +301,58 @@ If `postprocessing=true`, some colors might be replaced with `0` (the "neutral"
305301"""
306302function acyclic_coloring (g:: AdjacencyGraph , order:: AbstractOrder ; postprocessing:: Bool )
307303 # Initialize data structures
304+ S = pattern (g)
308305 nv = nb_vertices (g)
309306 ne = nb_edges (g)
310307 color = zeros (Int, nv)
311308 forbidden_colors = zeros (Int, nv)
312- first_neighbor = fill ((0 , 0 ), nv) # at first no neighbors have been encountered
309+ edge_to_index = Vector {Int} (undef, nnz (S))
310+ first_neighbor = fill ((0 , 0 , 0 ), nv) # at first no neighbors have been encountered
313311 first_visit_to_tree = fill ((0 , 0 ), ne)
314312 forest = Forest {Int} (ne)
315313 vertices_in_order = vertices (g, order)
316314
315+ # edge_to_index gives an index for each edge
316+ # use forbidden_colors (or color) for the offsets of each column
317+ offsets = forbidden_colors
318+ counter = 0
319+ rvS = rowvals (S)
320+ for j in axes (S, 2 )
321+ for k in nzrange (S, j)
322+ i = rvS[k]
323+ if i > j
324+ counter += 1
325+ edge_to_index[k] = counter
326+ k2 = S. colptr[i] + offsets[i]
327+ edge_to_index[k2] = counter
328+ offsets[i] += 1
329+ end
330+ end
331+ end
332+ fill! (offsets, 0 )
333+ # Note that we don't need to do that for bicoloring,
334+ # we can build that in the same time than the transposed sparsity pattern of A
335+
317336 for v in vertices_in_order
318337 for w in neighbors (g, v)
319338 iszero (color[w]) && continue
320339 forbidden_colors[color[w]] = v
321340 end
322341 for w in neighbors (g, v)
323342 iszero (color[w]) && continue
324- for x in neighbors ( g, w)
325- iszero (color[x]) && continue
343+ for (ix, x) in enumerate ( neighbors2 ( g, w) )
344+ (w == x || iszero (color[x]) ) && continue
326345 if forbidden_colors[color[x]] != v
346+ index_wx = edge_to_index[S. colptr[w] + ix - 1 ]
327347 _prevent_cycle! (
328- v, w, x, color, first_visit_to_tree, forbidden_colors, forest
348+ v,
349+ w,
350+ x,
351+ index_wx,
352+ color,
353+ first_visit_to_tree,
354+ forbidden_colors,
355+ forest,
329356 )
330357 end
331358 end
@@ -336,22 +363,25 @@ function acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessin
336363 break
337364 end
338365 end
339- for w in neighbors (g, v) # grow two-colored stars around the vertex v
340- iszero (color[w]) && continue
341- _grow_star! (v, w, color, first_neighbor, forest)
366+ for (iw, w) in enumerate (neighbors2 (g, v)) # grow two-colored stars around the vertex v
367+ (v == w || iszero (color[w])) && continue
368+ index_vw = edge_to_index[S. colptr[v] + iw - 1 ]
369+ _grow_star! (v, w, index_vw, color, first_neighbor, forest)
342370 end
343- for w in neighbors ( g, v)
344- iszero (color[w]) && continue
345- for x in neighbors ( g, w)
346- (x == v || iszero (color[x])) && continue
371+ for (iw, w) in enumerate ( neighbors2 ( g, v) )
372+ (v == w || iszero (color[w]) ) && continue
373+ for (ix, x) in enumerate ( neighbors2 ( g, w) )
374+ (w == x || x == v || iszero (color[x])) && continue
347375 if color[x] == color[v]
348- _merge_trees! (v, w, x, forest) # merge trees T₁ ∋ vw and T₂ ∋ wx if T₁ != T₂
376+ index_vw = edge_to_index[S. colptr[v] + iw - 1 ]
377+ index_wx = edge_to_index[S. colptr[w] + ix - 1 ]
378+ _merge_trees! (v, w, x, index_vw, index_wx, forest) # merge trees T₁ ∋ vw and T₂ ∋ wx if T₁ != T₂
349379 end
350380 end
351381 end
352382 end
353383
354- tree_set = TreeSet (forest, nb_vertices (g) )
384+ tree_set = TreeSet (g, forest, edge_to_index )
355385 if postprocessing
356386 # Reuse the vector forbidden_colors to compute offsets during post-processing
357387 postprocess! (color, tree_set, g, forbidden_colors)
@@ -364,17 +394,16 @@ function _prevent_cycle!(
364394 v:: Integer ,
365395 w:: Integer ,
366396 x:: Integer ,
397+ index_wx:: Integer ,
367398 color:: AbstractVector{<:Integer} ,
368399 # modified
369400 first_visit_to_tree:: AbstractVector{<:Tuple} ,
370401 forbidden_colors:: AbstractVector{<:Integer} ,
371402 forest:: Forest{<:Integer} ,
372403)
373- wx = _sort (w, x)
374- id = find_root! (forest, wx) # The edge wx belongs to the 2-colored tree T, represented by an edge with an integer ID
404+ id = find_root! (forest, index_wx) # The edge wx belongs to the 2-colored tree T, represented by an edge with an integer ID
375405 (p, q) = first_visit_to_tree[id]
376406 if p != v # T is being visited from vertex v for the first time
377- vw = _sort (v, w)
378407 first_visit_to_tree[id] = (v, w)
379408 elseif q != w # T is connected to vertex v via at least two edges
380409 forbidden_colors[color[x]] = v
@@ -386,21 +415,19 @@ function _grow_star!(
386415 # not modified
387416 v:: Integer ,
388417 w:: Integer ,
418+ index_vw:: Integer ,
389419 color:: AbstractVector{<:Integer} ,
390420 # modified
391421 first_neighbor:: AbstractVector{<:Tuple} ,
392422 forest:: Forest{<:Integer} ,
393423)
394- vw = _sort (v, w)
395- push! (forest, vw) # Create a new tree T_{vw} consisting only of edge vw
396- (p, q) = first_neighbor[color[w]]
424+ # Create a new tree T_{vw} consisting only of edge vw
425+ (p, q, index_pq) = first_neighbor[color[w]]
397426 if p != v # a neighbor of v with color[w] encountered for the first time
398- first_neighbor[color[w]] = (v, w)
427+ first_neighbor[color[w]] = (v, w, index_vw )
399428 else # merge T_{vw} with a two-colored star being grown around v
400- vw = _sort (v, w)
401- pq = _sort (p, q)
402- root1 = find_root! (forest, vw)
403- root2 = find_root! (forest, pq)
429+ root1 = find_root! (forest, index_vw)
430+ root2 = find_root! (forest, index_pq)
404431 root_union! (forest, root1, root2)
405432 end
406433 return nothing
@@ -411,13 +438,13 @@ function _merge_trees!(
411438 v:: Integer ,
412439 w:: Integer ,
413440 x:: Integer ,
441+ index_vw:: Integer ,
442+ index_wx:: Integer ,
414443 # modified
415444 forest:: Forest{<:Integer} ,
416445)
417- vw = _sort (v, w)
418- wx = _sort (w, x)
419- root1 = find_root! (forest, vw)
420- root2 = find_root! (forest, wx)
446+ root1 = find_root! (forest, index_vw)
447+ root2 = find_root! (forest, index_wx)
421448 if root1 != root2
422449 root_union! (forest, root1, root2)
423450 end
@@ -438,10 +465,9 @@ struct TreeSet
438465 is_star:: Vector{Bool}
439466end
440467
441- function TreeSet (forest:: Forest{Int} , nvertices:: Int )
442- # Forest is a structure defined in forest.jl
443- # - forest.intmap: a dictionary that maps an edge (i, j) to an integer k
444- # - forest.num_trees: the number of trees in the forest
468+ function TreeSet (g:: AdjacencyGraph , forest:: Forest{Int} , edge_to_index:: Vector{Int} )
469+ S = pattern (g)
470+ nv = nb_vertices (g)
445471 nt = forest. num_trees
446472
447473 # dictionary that maps a tree's root to the index of the tree
@@ -451,38 +477,45 @@ function TreeSet(forest::Forest{Int}, nvertices::Int)
451477 # vector of dictionaries where each dictionary stores the neighbors of each vertex in a tree
452478 trees = [Dict {Int,Vector{Int}} () for i in 1 : nt]
453479
454- # counter of the number of roots found
455- k = 0
456- for edge in keys (forest. intmap)
457- i, j = edge
458- root = find_root! (forest, edge)
480+ # current number of roots found
481+ nr = 0
459482
460- # Update roots
461- if ! haskey (roots, root)
462- k += 1
463- roots[root] = k
464- end
483+ rvS = rowvals (S)
484+ for j in axes (S, 2 )
485+ for pos in nzrange (S, j)
486+ i = rvS[pos]
487+ if i > j
488+ index_ij = edge_to_index[pos]
489+ root = find_root! (forest, index_ij)
465490
466- # index of the tree T that contains this edge
467- index_tree = roots[root]
491+ # Update roots
492+ if ! haskey (roots, root)
493+ nr += 1
494+ roots[root] = nr
495+ end
468496
469- # Update the neighbors of i in the tree T
470- if ! haskey (trees[index_tree], i)
471- trees[index_tree][i] = [j]
472- else
473- push! (trees[index_tree][i], j)
474- end
497+ # index of the tree T that contains this edge
498+ index_tree = roots[root]
475499
476- # Update the neighbors of j in the tree T
477- if ! haskey (trees[index_tree], j)
478- trees[index_tree][j] = [i]
479- else
480- push! (trees[index_tree][j], i)
500+ # Update the neighbors of i in the tree T
501+ if ! haskey (trees[index_tree], i)
502+ trees[index_tree][i] = [j]
503+ else
504+ push! (trees[index_tree][i], j)
505+ end
506+
507+ # Update the neighbors of j in the tree T
508+ if ! haskey (trees[index_tree], j)
509+ trees[index_tree][j] = [i]
510+ else
511+ push! (trees[index_tree][j], i)
512+ end
513+ end
481514 end
482515 end
483516
484517 # degrees is a vector of integers that stores the degree of each vertex in a tree
485- degrees = Vector {Int} (undef, nvertices )
518+ degrees = Vector {Int} (undef, nv )
486519
487520 # reverse breadth first (BFS) traversal order for each tree in the forest
488521 reverse_bfs_orders = [Tuple{Int,Int}[] for i in 1 : nt]
0 commit comments