@@ -105,7 +105,7 @@ function vertices(bg::BipartiteGraph{T}, ::Val{side}, ::LargestFirst) where {T,s
105105end
106106
107107"""
108- DynamicDegreeBasedOrder{degtype,direction}
108+ DynamicDegreeBasedOrder{degtype,direction}(; reproduce_colpack=false)
109109
110110Instance of [`AbstractOrder`](@ref) which sorts vertices using a dynamically computed degree.
111111
@@ -117,6 +117,10 @@ Instance of [`AbstractOrder`](@ref) which sorts vertices using a dynamically com
117117- `degtype::Symbol`: can be `:forward` (for the forward degree) or `:back` (for the back degree)
118118- `direction::Symbol`: can be `:low2high` (if the order is defined from lowest to highest, i.e. `1` to `n`) or `:high2low` (if the order is defined from highest to lowest, i.e. `n` to `1`)
119119
120+ # Settings
121+
122+ - `reproduce_colpack::Bool`: whether to manage the buckets in the same way as the original ColPack implementation. When `reproduce_colpack=true`, we always append and remove vertices from the end of a bucket, which incurs a large performance penalty because every modification requires a circular permutation of the corresponding bucket. This setting is mostly for the purpose of reproducing past research results which rely on implementation details.
123+
120124# Concrete variants
121125
122126- [`IncidenceDegree`](@ref)
@@ -127,17 +131,28 @@ Instance of [`AbstractOrder`](@ref) which sorts vertices using a dynamically com
127131
128132- [_ColPack: Software for graph coloring and related problems in scientific computing_](https://dl.acm.org/doi/10.1145/2513109.2513110), Gebremedhin et al. (2013), Section 5
129133"""
130- struct DynamicDegreeBasedOrder{degtype,direction} <: AbstractOrder end
134+ struct DynamicDegreeBasedOrder{degtype,direction} <: AbstractOrder
135+ reproduce_colpack:: Bool
136+ end
137+
138+ function DynamicDegreeBasedOrder {degtype,direction} (;
139+ reproduce_colpack:: Bool = false
140+ ) where {degtype,direction}
141+ return DynamicDegreeBasedOrder {degtype,direction} (reproduce_colpack)
142+ end
131143
132144struct DegreeBuckets{T}
133145 degrees:: Vector{T}
134146 bucket_storage:: Vector{T}
135147 bucket_low:: Vector{T}
136148 bucket_high:: Vector{T}
137149 positions:: Vector{T}
150+ reproduce_colpack:: Bool
138151end
139152
140- function DegreeBuckets (:: Type{T} , degrees:: Vector{T} , dmax:: Integer ) where {T}
153+ function DegreeBuckets (
154+ :: Type{T} , degrees:: Vector{T} , dmax:: Integer ; reproduce_colpack:: Bool
155+ ) where {T}
141156 # number of vertices per degree class
142157 deg_count = zeros (T, dmax + 1 )
143158 for d in degrees
@@ -157,7 +172,9 @@ function DegreeBuckets(::Type{T}, degrees::Vector{T}, dmax::Integer) where {T}
157172 bucket_storage[positions[v]] = v
158173 deg_count[d + 1 ] -= 1
159174 end
160- return DegreeBuckets (degrees, bucket_storage, bucket_low, bucket_high, positions)
175+ return DegreeBuckets (
176+ degrees, bucket_storage, bucket_low, bucket_high, positions, reproduce_colpack
177+ )
161178end
162179
163180maxdeg (db:: DegreeBuckets ) = length (db. bucket_low) - 1
@@ -205,8 +222,42 @@ function pop_next_candidate!(db::DegreeBuckets; direction::Symbol)
205222 return candidate
206223end
207224
225+ function rotate_bucket_left! (db:: DegreeBuckets , d:: Integer )
226+ (; bucket_storage, bucket_high, bucket_low, positions) = db
227+ low, high = bucket_low[d + 1 ], bucket_high[d + 1 ]
228+ # remember first element v
229+ v = bucket_storage[low]
230+ # shift everyone else one index down
231+ for i in (low + 1 ): high
232+ w = bucket_storage[i]
233+ bucket_storage[i - 1 ] = w
234+ positions[w] = i - 1
235+ end
236+ # put v back at the end
237+ bucket_storage[high] = v
238+ positions[v] = high
239+ return nothing
240+ end
241+
242+ function rotate_bucket_right! (db:: DegreeBuckets , d:: Integer )
243+ (; bucket_storage, bucket_high, bucket_low, positions) = db
244+ low, high = bucket_low[d + 1 ], bucket_high[d + 1 ]
245+ # remember last element v
246+ v = bucket_storage[high]
247+ # shift everyone else one index up
248+ for i in (high - 1 ): - 1 : low
249+ w = bucket_storage[i]
250+ bucket_storage[i + 1 ] = w
251+ positions[w] = i + 1
252+ end
253+ # put v back at the start
254+ bucket_storage[low] = v
255+ positions[v] = low
256+ return nothing
257+ end
258+
208259function update_bucket! (db:: DegreeBuckets , v:: Integer ; degtype, direction)
209- (; degrees, bucket_storage, bucket_low, bucket_high, positions) = db
260+ (; degrees, bucket_storage, bucket_low, bucket_high, positions, reproduce_colpack ) = db
210261 d, p = degrees[v], positions[v]
211262 low, high = bucket_low[d + 1 ], bucket_high[d + 1 ]
212263 # select previous or next bucket for the move
@@ -227,11 +278,27 @@ function update_bucket!(db::DegreeBuckets, v::Integer; degtype, direction)
227278 # update v's stats
228279 degrees[v] = d_new
229280 positions[v] = low_new - 1
281+ if reproduce_colpack
282+ # move v from start to end of the next bucket, preserving order
283+ rotate_bucket_left! (db, d_new) # expensive
284+ end
230285 else
231- # move the vertex w located at the start of the current bucket to v's position (!= ColPack)
232- w = bucket_storage[low]
233- bucket_storage[p] = w
234- positions[w] = p
286+ if reproduce_colpack
287+ # move the vertex w located at the end of the current bucket to v's position
288+ w = bucket_storage[high]
289+ bucket_storage[p] = w
290+ positions[w] = p
291+ # explicitly put v at the end
292+ bucket_storage[high] = v
293+ positions[v] = high
294+ # move v from end to start of the current bucket, preserving order
295+ rotate_bucket_right! (db, d) # expensive
296+ else
297+ # move the vertex w located at the start of the current bucket to v's position (!= ColPack)
298+ w = bucket_storage[low]
299+ bucket_storage[p] = w
300+ positions[w] = p
301+ end
235302 # shrink current bucket from the left
236303 # morally we put v at the start and then ignore it
237304 bucket_low[d + 1 ] += 1
@@ -249,14 +316,16 @@ function update_bucket!(db::DegreeBuckets, v::Integer; degtype, direction)
249316end
250317
251318function vertices (
252- g:: AdjacencyGraph{T} , :: DynamicDegreeBasedOrder{degtype,direction}
319+ g:: AdjacencyGraph{T} , order :: DynamicDegreeBasedOrder{degtype,direction}
253320) where {T<: Integer ,degtype,direction}
254321 if degree_increasing (; degtype, direction)
255322 degrees = zeros (T, nb_vertices (g))
256323 else
257324 degrees = T[degree (g, v) for v in vertices (g)]
258325 end
259- db = DegreeBuckets (T, degrees, maximum_degree (g))
326+ db = DegreeBuckets (
327+ T, degrees, maximum_degree (g); reproduce_colpack= order. reproduce_colpack
328+ )
260329 π = T[]
261330 sizehint! (π, nb_vertices (g))
262331 for _ in 1 : nb_vertices (g)
@@ -272,7 +341,7 @@ function vertices(
272341end
273342
274343function vertices (
275- g:: BipartiteGraph{T} , :: Val{side} , :: DynamicDegreeBasedOrder{degtype,direction}
344+ g:: BipartiteGraph{T} , :: Val{side} , order :: DynamicDegreeBasedOrder{degtype,direction}
276345) where {T<: Integer ,side,degtype,direction}
277346 other_side = 3 - side
278347 # compute dist-2 degrees in an optimized way
@@ -294,7 +363,7 @@ function vertices(
294363 degrees = degrees_dist2
295364 end
296365 maxd2 = maximum (degrees_dist2)
297- db = DegreeBuckets (T, degrees, maxd2)
366+ db = DegreeBuckets (T, degrees, maxd2; reproduce_colpack = order . reproduce_colpack )
298367 π = T[]
299368 sizehint! (π, n)
300369 visited = falses (n)
@@ -318,7 +387,7 @@ function vertices(
318387end
319388
320389"""
321- IncidenceDegree()
390+ IncidenceDegree(; reproduce_colpack=false )
322391
323392Instance of [`AbstractOrder`](@ref) which sorts vertices from lowest to highest using the dynamic back degree.
324393
@@ -332,7 +401,7 @@ Instance of [`AbstractOrder`](@ref) which sorts vertices from lowest to highest
332401const IncidenceDegree = DynamicDegreeBasedOrder{:back ,:low2high }
333402
334403"""
335- SmallestLast()
404+ SmallestLast(; reproduce_colpack=false )
336405
337406Instance of [`AbstractOrder`](@ref) which sorts vertices from highest to lowest using the dynamic back degree.
338407
@@ -346,7 +415,7 @@ Instance of [`AbstractOrder`](@ref) which sorts vertices from highest to lowest
346415const SmallestLast = DynamicDegreeBasedOrder{:back ,:high2low }
347416
348417"""
349- DynamicLargestFirst()
418+ DynamicLargestFirst(; reproduce_colpack=false )
350419
351420Instance of [`AbstractOrder`](@ref) which sorts vertices from lowest to highest using the dynamic forward degree.
352421
0 commit comments