pub fn transitive_closure(
graph: &SqliteGraph,
bounds: Option<TransitiveClosureBounds>,
) -> Result<AHashMap<(i64, i64), bool>, SqliteGraphError>Expand description
Computes transitive closure for all-pairs reachability.
Transitive closure determines which nodes can reach which other nodes in the graph.
Returns a HashMap where keys are (source, target) pairs and values are always true
for reachable pairs. Self-reachability is included (every node can reach itself).
§Arguments
graph- The graph to analyzebounds- Optional bounds to limit computation
§Returns
HashMap mapping (source_id, target_id) -> true for all reachable pairs.
§Complexity
- Time: O(|V| * (|V| + |E|)) worst case for unbounded
- Space: O(|V|²) for full transitive closure
§Algorithm
Uses BFS from each source node:
- For each source node, run BFS limited by max_depth
- Track visited nodes to prevent infinite loops on cycles
- Store (source, target) pairs for all reachable nodes
- Self-reachability is always true (node can reach itself)
§Bounds Behavior
max_depth- Limits BFS depth from each sourcemax_sources- Processes only first N source nodesmax_pairs- Stops early after finding N reachable pairs
§Example
ⓘ
use sqlitegraph::{SqliteGraph, algo::transitive_closure};
let graph = SqliteGraph::open_in_memory()?;
// ... add nodes and edges ...
// Full transitive closure
let closure = transitive_closure(&graph, None)?;
// Query: can node 1 reach node 5?
let can_reach = closure.get(&(1, 5)).copied().unwrap_or(false);
// Count reachable nodes from source 1
let reachable_count: usize = closure.iter()
.filter(|((&src, _), _)| src == 1)
.count();§See Also
transitive_closure_with_progress- For progress trackingTransitiveClosureBounds- For limiting computation