Some questions require knowing the distance between every pair of points in a network, not just from one start. Travel-time matrices for delivery planning. Latency tables between data centers. Reachability matrices for org charts. The Floyd-Warshall algorithm fills the entire table at once and runs in time proportional to the cube of the number of points. This sounds expensive but is competitive for networks up to about a thousand nodes — fast enough to recompute on demand for many business uses. Rust's petgraph implements it directly. When your network is larger than a few thousand nodes and you need all pairs, run the single-source router (Dijkstra) once per starting point in parallel instead. When you need a few specific pairs, run it once per pair.
10
Distance from everywhere to everywhere
Three nested loops and a table. When the network is small and you want every distance, this is the answer.
-
floyd_warshallfills the entire pair-wise distance table in one call. On the petgraph API it returns aHashMapkeyed by(NodeIndex, NodeIndex)— perfect for caching a delivery-zone travel matrix you precompute once and serve from forever.use petgraph::algo::floyd_warshall; use petgraph::graph::{DiGraph, NodeIndex}; use std::collections::HashMap; fn travel_matrix(zones: &DiGraph<&str, u32>) -> HashMap<(NodeIndex, NodeIndex), u32> { floyd_warshall(zones, |e| *e.weight()) .expect("no negative cycles in travel times") } - If
NodeIndexhas been showing up since page 7 without an introduction, here it is. ANodeIndexis petgraph's handle for a node — a small, cheap-to-copy ID the library hands you when you add a node, which you then pass back to every subsequent operation that needs to refer to that node. It is NOT the node's payload (the&strlabel, theCustomerstruct, whatever you stored). Internally, petgraph keeps nodes in aVec<T>— that's Rust's growable list type (we saw it back in the schedule checker), a contiguous block of values indexed by integers0, 1, 2, …. When people say "vector" in Rust they meanVec, not the math-class arrow.NodeIndexis a wrapper around the integer position into thatVec. That's why every graph operation isO(1), why the stored values don't need to be hashable or unique, and why this page can key aHashMap<(NodeIndex, NodeIndex), u32>on node-pair tuples to a distance. Two named nodes can carry identical labels; theirNodeIndexhandles are still distinct.use petgraph::graph::{DiGraph, NodeIndex}; use std::collections::HashMap; let mut g = DiGraph::<&str, u32>::new(); // add_node returns the handle for the node you just stored. let a: NodeIndex = g.add_node("Alice"); // NodeIndex(0) let b: NodeIndex = g.add_node("Bob"); // NodeIndex(1) let c: NodeIndex = g.add_node("Carol"); // NodeIndex(2) // Every subsequent operation takes the handle, never the label. g.add_edge(a, b, 5); g.add_edge(b, c, 3); // Look up the stored payload from the handle: let name = g[a]; // → "Alice" // NodeIndex is Copy + Eq + Hash, so it works as a HashMap key. let mut distances: HashMap<NodeIndex, u32> = HashMap::new(); distances.insert(a, 0); distances.insert(b, 5); // Mental model: // // internal Vec of node payloads: // index 0 → "Alice" // index 1 → "Bob" // index 2 → "Carol" // // NodeIndex(1) ─is the address of─► index 1 ← "Bob"'s payload // // The label is data the graph happens to be storing at that slot. // The NodeIndex is how you refer to the slot.