Skip to content

Commit 61d309c

Browse files
authored
Sparse hashing (#74)
performance fix for `canonical_id(::SparseNautyGraph)`; hash values unchanged
1 parent fc9ec9a commit 61d309c

2 files changed

Lines changed: 24 additions & 5 deletions

File tree

src/nauty.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -673,8 +673,8 @@ function _SHAhash_adjacency(sg, labels)
673673
throw(ArgumentError("got $(length(labels)) labels for a graph on $(sg.nv) vertices"))
674674
end
675675
ctx = SHA.SHA256_CTX()
676-
for i in Base.OneTo(sg.nv)
677-
_shaupdate!(ctx, _fadj_0based(sg, i))
676+
for adjacency in _fadjs_0based(sg)
677+
_shaupdate!(ctx, adjacency)
678678
end
679679
_shaupdate!(ctx, labels)
680680
return _digest(ctx)

src/sparsenautygraph.jl

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,30 @@ end
270270
@inline function _fadj_0based(g::SparseGraphRep, v::Integer)
271271
# return the adjacency of vertex `v` as an array over nauty's edge list
272272
# the resulting indices are zero-based
273-
# only the neighbour list is wrapped, rather than all three of nauty's arrays
274-
offset = unsafe_load(g.v, v)
275-
degree = unsafe_load(g.d, v)
273+
offset, degree = _adjacencybounds(g, v)
276274
return unsafe_wrap(Array, g.e + offset * sizeof(Cint), degree)
277275
end
276+
277+
# Where vertex `v`'s neighbours sit in the edge list, as a zero-based offset and a length (degree).
278+
@inline _adjacencybounds(g::SparseGraphRep, v::Integer) = (unsafe_load(g.v, v), unsafe_load(g.d, v))
279+
@inline _adjacencybounds(g::SparseNautyGraph, v::Integer) = (g.v[v], g.d[v])
280+
281+
# The whole edge list as one array.
282+
@inline _edgelist(g::SparseNautyGraph) = g.e
283+
@inline function _edgelist(g::SparseGraphRep)
284+
# nauty leaves the pointer null for a graph with no edges, which must not be wrapped
285+
return iszero(g.nde) ? Cint[] : unsafe_wrap(Array, g.e, g.nde)
286+
end
287+
288+
@inline _adjacencyview(edgelist, offset, degree) = @view edgelist[(offset + 1):(offset + degree)]
289+
290+
# Iterate the adjacency of every vertex of `g` in order, as zero-based views into its edge list.
291+
# Unlike calling `_fadj_0based` per vertex, this wraps nauty's edge array only once, which matters
292+
# for callers that walk the whole graph.
293+
@inline function _fadjs_0based(g)
294+
edgelist = _edgelist(g)
295+
return (_adjacencyview(edgelist, _adjacencybounds(g, v)...) for v in Base.OneTo(Int(g.nv)))
296+
end
278297
@inline function Graphs.outneighbors(g::SparseNautyGraph, v::Integer)
279298
# following the Graph.jl implementation, there is no boundscheck here
280299
return (zero2one(g.e[i]) for i in (zero2one(g.v[v])):(g.v[v] + g.d[v]))

0 commit comments

Comments
 (0)