@@ -145,28 +145,50 @@ $COLPACK_WARNING
145145
146146- [_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
147147"""
148- struct DynamicDegreeBasedOrder{degtype,direction} <: AbstractOrder
149- reproduce_colpack:: Bool
150- end
148+ struct DynamicDegreeBasedOrder{degtype,direction,reproduce_colpack} <: AbstractOrder end
151149
152150function DynamicDegreeBasedOrder {degtype,direction} (;
153151 reproduce_colpack:: Bool = false
154152) where {degtype,direction}
155- return DynamicDegreeBasedOrder {degtype,direction} (reproduce_colpack )
153+ return DynamicDegreeBasedOrder {degtype,direction,reproduce_colpack} ( )
156154end
157155
158- struct DegreeBuckets{T}
156+ abstract type AbstractDegreeBuckets{T} end
157+
158+ struct DegreeBucketsColPack{T} <: AbstractDegreeBuckets{T}
159+ degrees:: Vector{T}
160+ buckets:: Vector{Vector{T}}
161+ positions:: Vector{T}
162+ end
163+
164+ struct DegreeBucketsFast{T} <: AbstractDegreeBuckets{T}
159165 degrees:: Vector{T}
160166 bucket_storage:: Vector{T}
161167 bucket_low:: Vector{T}
162168 bucket_high:: Vector{T}
163169 positions:: Vector{T}
164- reproduce_colpack:: Bool
165170end
166171
167- function DegreeBuckets (
168- :: Type{T} , degrees:: Vector{T} , dmax:: Integer ; reproduce_colpack:: Bool
169- ) where {T}
172+ function DegreeBucketsColPack (:: Type{T} , degrees:: Vector{T} , dmax:: Integer ) where {T}
173+ # number of vertices per degree class
174+ deg_count = zeros (T, dmax + 1 )
175+ for d in degrees
176+ deg_count[d + 1 ] += 1
177+ end
178+ # one vector per bucket
179+ buckets = [Vector {T} (undef, deg_count[d + 1 ]) for d in 0 : dmax]
180+ positions = similar (degrees, T)
181+ # assign each vertex to the correct local position inside its bucket
182+ for v in eachindex (positions, degrees)
183+ d = degrees[v]
184+ positions[v] = length (buckets[d + 1 ]) - deg_count[d + 1 ] + 1
185+ buckets[d + 1 ][positions[v]] = v
186+ deg_count[d + 1 ] -= 1
187+ end
188+ return DegreeBucketsColPack (degrees, buckets, positions)
189+ end
190+
191+ function DegreeBucketsFast (:: Type{T} , degrees:: Vector{T} , dmax:: Integer ) where {T}
170192 # number of vertices per degree class
171193 deg_count = zeros (T, dmax + 1 )
172194 for d in degrees
@@ -177,7 +199,7 @@ function DegreeBuckets(
177199 bucket_low = similar (bucket_high)
178200 bucket_low[1 ] = 1
179201 bucket_low[2 : end ] .= @view (bucket_high[1 : (end - 1 )]) .+ 1
180- # assign each vertex to the correct position inside its degree class
202+ # assign each vertex to the correct global position inside its bucket
181203 bucket_storage = similar (degrees, T)
182204 positions = similar (degrees, T)
183205 for v in eachindex (positions, degrees)
@@ -186,12 +208,18 @@ function DegreeBuckets(
186208 bucket_storage[positions[v]] = v
187209 deg_count[d + 1 ] -= 1
188210 end
189- return DegreeBuckets (
190- degrees, bucket_storage, bucket_low, bucket_high, positions, reproduce_colpack
191- )
211+ return DegreeBucketsFast (degrees, bucket_storage, bucket_low, bucket_high, positions)
192212end
193213
194- maxdeg (db:: DegreeBuckets ) = length (db. bucket_low) - 1
214+ maxdeg (db:: DegreeBucketsColPack ) = length (db. buckets) - 1
215+ maxdeg (db:: DegreeBucketsFast ) = length (db. bucket_low) - 1
216+
217+ function nonempty_bucket (db:: DegreeBucketsFast , d:: Integer )
218+ return db. bucket_high[d + 1 ] >= db. bucket_low[d + 1 ]
219+ end
220+ function nonempty_bucket (db:: DegreeBucketsColPack , d:: Integer )
221+ return ! isempty (db. buckets[d + 1 ])
222+ end
195223
196224function degree_increasing (; degtype, direction)
197225 increasing =
@@ -200,78 +228,52 @@ function degree_increasing(; degtype, direction)
200228 return increasing
201229end
202230
203- function mark_ordered! (db:: DegreeBuckets {T} , v:: Integer ) where {T}
231+ function mark_ordered! (db:: AbstractDegreeBuckets {T} , v:: Integer ) where {T}
204232 db. degrees[v] = - 1
205233 db. positions[v] = typemin (T)
206234 return nothing
207235end
208236
209- already_ordered (db:: DegreeBuckets , v:: Integer ) = db. degrees[v] == - 1
237+ already_ordered (db:: AbstractDegreeBuckets , v:: Integer ) = db. degrees[v] == - 1
210238
211- function pop_next_candidate! (db:: DegreeBuckets ; direction:: Symbol )
212- (; bucket_storage, bucket_low, bucket_high) = db
239+ function pop_next_candidate! (db:: AbstractDegreeBuckets ; direction:: Symbol )
213240 dmax = maxdeg (db)
214241 if direction == :low2high
215242 candidate_degree = dmax + 1
216243 for d in dmax: - 1 : 0
217- if bucket_high[d + 1 ] >= bucket_low[d + 1 ] # not empty
244+ if nonempty_bucket (db, d)
218245 candidate_degree = d
219246 break
220247 end
221248 end
222249 else
223250 candidate_degree = - 1
224251 for d in 0 : dmax
225- if bucket_high[d + 1 ] >= bucket_low[d + 1 ] # not empty
252+ if nonempty_bucket (db, d)
226253 candidate_degree = d
227254 break
228255 end
229256 end
230257 end
231- high = bucket_high[candidate_degree + 1 ]
232- candidate = bucket_storage[high]
233- bucket_storage[high] = - 1
234- bucket_high[candidate_degree + 1 ] -= 1
258+ if db isa DegreeBucketsColPack
259+ (; buckets) = db
260+ bucket = buckets[candidate_degree + 1 ]
261+ candidate = pop! (bucket)
262+ else
263+ (; bucket_storage, bucket_high) = db
264+ high = bucket_high[candidate_degree + 1 ]
265+ candidate = bucket_storage[high]
266+ bucket_storage[high] = - 1
267+ bucket_high[candidate_degree + 1 ] -= 1
268+ end
235269 mark_ordered! (db, candidate)
236270 return candidate
237271end
238272
239- function rotate_bucket_left! (db:: DegreeBuckets , d:: Integer )
240- (; bucket_storage, bucket_high, bucket_low, positions) = db
241- low, high = bucket_low[d + 1 ], bucket_high[d + 1 ]
242- # remember first element v
243- v = bucket_storage[low]
244- # shift everyone else one index down
245- for i in (low + 1 ): high
246- w = bucket_storage[i]
247- bucket_storage[i - 1 ] = w
248- positions[w] = i - 1
249- end
250- # put v back at the end
251- bucket_storage[high] = v
252- positions[v] = high
253- return nothing
254- end
255-
256- function rotate_bucket_right! (db:: DegreeBuckets , d:: Integer )
257- (; bucket_storage, bucket_high, bucket_low, positions) = db
258- low, high = bucket_low[d + 1 ], bucket_high[d + 1 ]
259- # remember last element v
260- v = bucket_storage[high]
261- # shift everyone else one index up
262- for i in (high - 1 ): - 1 : low
263- w = bucket_storage[i]
264- bucket_storage[i + 1 ] = w
265- positions[w] = i + 1
266- end
267- # put v back at the start
268- bucket_storage[low] = v
269- positions[v] = low
270- return nothing
271- end
272-
273- function update_bucket! (db:: DegreeBuckets , v:: Integer ; degtype:: Symbol , direction:: Symbol )
274- (; degrees, bucket_storage, bucket_low, bucket_high, positions, reproduce_colpack) = db
273+ function update_bucket! (
274+ db:: DegreeBucketsFast , v:: Integer ; degtype:: Symbol , direction:: Symbol
275+ )
276+ (; degrees, bucket_storage, bucket_low, bucket_high, positions) = db
275277 d, p = degrees[v], positions[v]
276278 low, high = bucket_low[d + 1 ], bucket_high[d + 1 ]
277279 # select previous or next bucket for the move
@@ -292,27 +294,11 @@ function update_bucket!(db::DegreeBuckets, v::Integer; degtype::Symbol, directio
292294 # update v's stats
293295 degrees[v] = d_new
294296 positions[v] = low_new - 1
295- if reproduce_colpack
296- # move v from start to end of the next bucket, preserving order
297- rotate_bucket_left! (db, d_new) # expensive
298- end
299297 else
300- if reproduce_colpack
301- # move the vertex w located at the end of the current bucket to v's position
302- w = bucket_storage[high]
303- bucket_storage[p] = w
304- positions[w] = p
305- # explicitly put v at the end
306- bucket_storage[high] = v
307- positions[v] = high
308- # move v from end to start of the current bucket, preserving order
309- rotate_bucket_right! (db, d) # expensive
310- else
311- # move the vertex w located at the start of the current bucket to v's position (!= ColPack)
312- w = bucket_storage[low]
313- bucket_storage[p] = w
314- positions[w] = p
315- end
298+ # move the vertex w located at the start of the current bucket to v's position (!= ColPack)
299+ w = bucket_storage[low]
300+ bucket_storage[p] = w
301+ positions[w] = p
316302 # shrink current bucket from the left
317303 # morally we put v at the start and then ignore it
318304 bucket_low[d + 1 ] += 1
@@ -329,15 +315,42 @@ function update_bucket!(db::DegreeBuckets, v::Integer; degtype::Symbol, directio
329315 return nothing
330316end
331317
318+ function update_bucket! (
319+ db:: DegreeBucketsColPack , v:: Integer ; degtype:: Symbol , direction:: Symbol
320+ )
321+ (; degrees, buckets, positions) = db
322+ d, p = degrees[v], positions[v]
323+ bucket = buckets[d + 1 ]
324+ # select previous or next bucket for the move
325+ d_new = degree_increasing (; degtype, direction) ? d + 1 : d - 1
326+ bucket_new = buckets[d_new + 1 ]
327+ # put v at the end of its bucket by swapping
328+ w = bucket[end ]
329+ bucket[p] = w
330+ positions[w] = p
331+ bucket[end ] = v
332+ positions[v] = length (bucket)
333+ # move v from the old bucket to the new one
334+ @assert pop! (bucket) == v
335+ push! (bucket_new, v)
336+ degrees[v] = d_new
337+ positions[v] = length (bucket_new)
338+ return nothing
339+ end
340+
332341function vertices (
333- g:: AdjacencyGraph{T} , order :: DynamicDegreeBasedOrder{degtype,direction}
334- ) where {T<: Integer ,degtype,direction}
342+ g:: AdjacencyGraph{T} , :: DynamicDegreeBasedOrder{degtype,direction,reproduce_colpack }
343+ ) where {T<: Integer ,degtype,direction,reproduce_colpack }
335344 true_degrees = degrees = T[degree (g, v) for v in vertices (g)]
336345 max_degrees = maximum (true_degrees)
337346 if degree_increasing (; degtype, direction)
338347 fill! (degrees, zero (T))
339348 end
340- db = DegreeBuckets (T, degrees, max_degrees; reproduce_colpack= order. reproduce_colpack)
349+ db = if reproduce_colpack
350+ DegreeBucketsColPack (T, degrees, max_degrees)
351+ else
352+ DegreeBucketsFast (T, degrees, max_degrees)
353+ end
341354 nv = nb_vertices (g)
342355 π = Vector {T} (undef, nv)
343356 index_π = (direction == :low2high ) ? (1 : nv) : (nv: - 1 : 1 )
@@ -354,8 +367,10 @@ function vertices(
354367end
355368
356369function vertices (
357- g:: BipartiteGraph{T} , :: Val{side} , order:: DynamicDegreeBasedOrder{degtype,direction}
358- ) where {T<: Integer ,side,degtype,direction}
370+ g:: BipartiteGraph{T} ,
371+ :: Val{side} ,
372+ :: DynamicDegreeBasedOrder{degtype,direction,reproduce_colpack} ,
373+ ) where {T<: Integer ,side,degtype,direction,reproduce_colpack}
359374 other_side = 3 - side
360375 # compute dist-2 degrees in an optimized way
361376 n = nb_vertices (g, Val (side))
@@ -375,7 +390,11 @@ function vertices(
375390 if degree_increasing (; degtype, direction)
376391 fill! (degrees, zero (T))
377392 end
378- db = DegreeBuckets (T, degrees, maxd2; reproduce_colpack= order. reproduce_colpack)
393+ db = if reproduce_colpack
394+ DegreeBucketsColPack (T, degrees, maxd2)
395+ else
396+ DegreeBucketsFast (T, degrees, maxd2)
397+ end
379398 π = Vector {T} (undef, n)
380399 index_π = (direction == :low2high ) ? (1 : n) : (n: - 1 : 1 )
381400 for index in index_π
@@ -406,7 +425,9 @@ $COLPACK_WARNING
406425
407426- [`DynamicDegreeBasedOrder`](@ref)
408427"""
409- const IncidenceDegree = DynamicDegreeBasedOrder{:back ,:low2high }
428+ function IncidenceDegree (; reproduce_colpack:: Bool = false )
429+ DynamicDegreeBasedOrder {:back,:low2high,reproduce_colpack} ()
430+ end
410431
411432"""
412433 SmallestLast(; reproduce_colpack=false)
@@ -419,7 +440,9 @@ $COLPACK_WARNING
419440
420441- [`DynamicDegreeBasedOrder`](@ref)
421442"""
422- const SmallestLast = DynamicDegreeBasedOrder{:back ,:high2low }
443+ function SmallestLast (; reproduce_colpack:: Bool = false )
444+ DynamicDegreeBasedOrder {:back,:high2low,reproduce_colpack} ()
445+ end
423446
424447"""
425448 DynamicLargestFirst(; reproduce_colpack=false)
@@ -432,7 +455,9 @@ $COLPACK_WARNING
432455
433456- [`DynamicDegreeBasedOrder`](@ref)
434457"""
435- const DynamicLargestFirst = DynamicDegreeBasedOrder{:forward ,:low2high }
458+ function DynamicLargestFirst (; reproduce_colpack:: Bool = false )
459+ DynamicDegreeBasedOrder {:forward,:low2high,reproduce_colpack} ()
460+ end
436461
437462"""
438463 PerfectEliminationOrder(elimination_algorithm=CliqueTrees.MCS())
@@ -461,7 +486,10 @@ function all_orders()
461486 RandomOrder (),
462487 LargestFirst (),
463488 SmallestLast (),
489+ SmallestLast (; reproduce_colpack= true ),
464490 IncidenceDegree (),
491+ IncidenceDegree (; reproduce_colpack= true ),
465492 DynamicLargestFirst (),
493+ DynamicLargestFirst (; reproduce_colpack= true ),
466494 ]
467495end
0 commit comments