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::Integeris the list of neighbors ofPeriodicVertex{N}(i). Performance-wise, this operation is a simple access on the underlying structure ofgso 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 ofxbut 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, sogshould not be modified while iterating overedges(g). The iterator object is aPeriodicGraphs.PeriodicEdgeIter.Graphs._neighborhoodhas a specialization forPeriodicGraphif 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
endIn 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
visitedbywidth = PeriodicGraphs.graph_width!(g) seen_size = nv(g)*(2*(1 + fld(depth-1, width)) + 1)^N visited = falses(seen_size)replace
x ∈ visitedbyvisited[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} <: AbstractEdgeIterEdge 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 PeriodicGraphs 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 DIterator type that yields the sequence of PeriodicVertex in list, each offset by the input ofs.
PeriodicGraphs.graph_width! — Functiongraph_width!(g::PeriodicGraph{N}) where NSet 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.