A first update in Python#
This program builds a four-vertex graph, computes shortest paths from vertex 0, and then applies
a batch with dyng.sssp.update(), which changes the graph and brings the result up to date.
It is examples/python/first_update.py, the Python twin of A first update in C++; the test
suite runs it on both CPU backends and checks that it prints exactly this:
invalidated 2, affected 2
distances 0 4 1 2
parents -1 0 0 2
import sys
import dyng
def main(backend: str = "openmp") -> None:
res = dyng.Resources(backend) # "sequential" or "openmp" in the CPU wheel
# Edges 0->1 (4), 0->2 (1), 2->1 (2), 1->3 (1): sources, destinations, weights.
g = dyng.Graph.from_edges([0, 0, 2, 1], [1, 2, 1, 3], [4, 1, 2, 1], resources=res)
tree = dyng.sssp.compute(g, source=0) # the canonical tree: lowest-id ties
batch = dyng.EdgeBatch(insert=([2], [3], [1]), delete=([2], [1])) # +2->3 (1), -2->1
st = dyng.sssp.update(g, batch, tree) # applies the batch to g and repairs the tree
print(f"invalidated {st.invalidated}, affected {st.affected}")
print("distances", *tree.distances.tolist())
print("parents", *tree.parents.tolist()) # distances 0 4 1 2, parents -1 0 0 2
if __name__ == "__main__":
main(*sys.argv[1:2])
What happened:
dyng.Resources("openmp")chose the backend (the CPU wheel has"sequential"and"openmp"; Backends and resources). The graph keeps its resources, so the calls below need noresources=argument.Graph.from_edges(src, dst, weights)built the graph. The id arrays are Python lists, so the vertex ids are int32 (an int64 NumPy array would give int64 ids: dtypes are never narrowed silently; Python API).dyng.sssp.compute()produced the static result, the canonical shortest-path tree: distances (0, 3, 1, 4), vertex 1 reached through vertex 2.dyng.sssp.update()applied the batch tog(its version went up by one) and repaired the tree: deleting the tree edge (2, 1) invalidated the subtree below vertex 1 ({1, 3}), and the insertion (2, 3) gave vertex 3 a shorter path.stholds the counters of this update.tree.distancesandtree.parentsaredyng.Arrayviews of the result’s memory (no copy);tolist()andto_numpy()copy them. After the next update oftreethese views raiseStaleResultError: read the properties again (Results and versions).
Keeping several results on one graph current takes one call, which applies the batch once:
import dyng
g = dyng.Graph.from_edges([0, 0, 2, 1, 3], [1, 2, 1, 3, 0], [4, 1, 2, 1, 1])
tree = dyng.sssp.compute(g, source=0)
hist = dyng.cycle_count.compute(g, max_length=4) # cycles of length 2..4 (weights ignored)
batch = dyng.EdgeBatch(insert=([2], [3], [1]), delete=([2], [1]))
st_tree, st_hist = dyng.update(g, batch, tree, hist)
print(tree.distances.tolist(), hist.counts.tolist(), st_hist.cycles_removed, st_hist.cycles_added)
[0, 4, 1, 2] [0, 0, 0, 2, 0] 1 1
dyng.sssp.update(g, batch, tree) alone would have left hist stale: its next use raises
dyng.StaleResultError.
The same steps from the command line, on files in MOSP’s formats, are in Command-line interface
(dyng sssp compute and dyng sssp update) and in the tutorial
Dynamic shortest paths on MOSP files (C++). The next steps are the algorithm pages, sssp: dynamic single-source shortest paths,
mosp: dynamic multi-objective shortest paths (several weights per edge: multi-objective shortest paths) and
cycle_count: exact k-bounded directed simple-cycle histograms, which have longer Python and CLI examples; the tutorial
algorithms dynamic_bfs: BFS levels under edge batches (tutorial) and triangle_delta: the triangle count under edge batches (tutorial) show how an
algorithm is written.