Neighborhoods and graph traversals
Manual
The AbstractGraph
API for exploring neighbors and traversing graphs has to be somewhat adapted to account for the specific aspects of PeriodicGraphs
. Here, we present a list of notes relative to these aspects, where g
is a PeriodicGraph{N}
:
neighbors(g, i)
wherei::Integer
is the list of neighbors ofPeriodicVertex{N}(i)
. Performance-wise, this operation is a simple access on the underlying structure ofg
so it is very fast, but the returnedVector{PeriodicVertex{N}}
should not be modified.neighbors(g, x)
wherex::PeriodicVertex{N}
is an iterator over the neighbors ofx
but not an array. The iterator object is aPeriodicGraphs.OffsetVertexIterator
.edges(g)
is an iterator over the direct edges ofg
. Every edge representative will thus be visited exactly once. It is invalidated by any change tog
, sog
should not be modified while iterating overedges(g)
. The iterator object is aPeriodicGraphs.PeriodicEdgeIter
.Graphs._neighborhood
has a specialization forPeriodicGraph
if required.
A typical BFS algorithm on g
can be implemented like so:
function bfs(g::PeriodicGraph{N}, starting_vertex, depth) where N
visited = Set{PeriodicVertex{N}}(starting_vertex)
Q = Tuple{Int,PeriodicVertex{N}}[(0, starting_vertex)]
for (distance, u) in Q
distance > depth && break
# do stuff with u
for x in neighbors(g, u)
x ∈ visited && continue
push!(x, visited)
# do stuff with x
push!(Q, (distance+1, x))
end
# do more stuff
end
# return something
end
In some cases however, the Set
-interface can end up being the bottleneck. In this kind of situation, it may be better to:
replace the initialization of
visited
bywidth = PeriodicGraphs.graph_width!(g) seen_size = nv(g)*(2*(1 + fld(depth-1, width)) + 1)^N visited = falses(seen_size)
replace
x ∈ visited
byvisited[hash_position(x, g)]
andreplace
push!(x, visited)
byvisited[hash_position(x, g)] = true
although some care should be taken since PeriodicGraphs.graph_width!
is only a heuristic.
Such algorithms can be used to compute the topological invariants like coordination_sequence
for example.
API
PeriodicGraphs.PeriodicEdgeIter
— TypePeriodicEdgeIter{N} <: AbstractEdgeIter
Edge iterator type for undirected N
-periodic graphs.
The iterator only yields edges in the form (u, v, ofs)
with either u < v
or u == v && ofs > zero(ofs)
. This is possible because PeriodicGraph
s are undirected, hence to each edge (u, v, ofs)
in the graph corresponds its reverse edge (v, u, .-ofs)
. The iterator thus yields each edge of the graph exactly once.
PeriodicGraphs.OffsetVertexIterator
— TypeOffsetVertexIterator{D} <: AbstractVector{PeriodicVertex{D}}
OffsetVertexIterator(ofs::SVector{D,Int}, list::AbstractVector{PeriodicVertex{D}}) where D
Iterator type that yields the sequence of PeriodicVertex
in list
, each offset by the input ofs
.
PeriodicGraphs.graph_width!
— Functiongraph_width!(g::PeriodicGraph{N}) where N
Set the width
internal field of the graph so that the for most n
∈ N*, the n
-th neighbor of any vertex v
of the initial cell is in a cell (i_1, i_2, ..., i_N)
such that max(abs.((i_1, i_2, ..., i_N))) ≤ 1 + fld((n - 1), width)
. Return the new width
.
This function is only a heuristic, it may produce a width
that does not satisfy the condition.
This function returns the current width
if it is not equal to -1
(internal value used to mark an unset width
). If you decide to modify the other internal fields of g
, it is probably a good idea to do g.width[] = -1
so that this function gets automatically called when needed, unless you are sure the width will not be affected by your change.