Skip to main content

impact_radius

Function impact_radius 

Source
pub fn impact_radius(
    graph: &SqliteGraph,
    source: i64,
    config: &ImpactRadiusConfig<'_>,
) -> Result<ImpactRadiusResult, SqliteGraphError>
Expand description

Computes the impact radius from a source node using bounded weighted BFS.

Impact radius computes the “blast zone” - all nodes within a specified weighted distance from a source node. This is useful for:

  • Failure impact analysis: What could be affected if this node fails?
  • Change propagation: What might need testing after this change?
  • Security blast zone: What’s the maximum potential damage radius?
  • Network lateral movement: How far could an attacker propagate?

§Arguments

  • graph - The graph to analyze
  • source - The source node ID (center of blast zone)
  • config - Configuration for radius computation

§Returns

Ok(ImpactRadiusResult) containing:

  • blast_zone - All nodes within max_distance
  • distances - Distance from source to each node
  • boundary - Nodes at exactly max_distance
  • size - Total nodes in blast zone

§Algorithm

Bounded breadth-first search with distance tracking:

  1. Initialize: distances[source] = 0.0, queue = [(source, 0 hops)]
  2. While queue not empty:
    • Pop (node, hops)
    • Skip if dist > max_distance (early termination)
    • Skip if max_hops Some() and hops >= max_hops
    • Add node to blast_zone
    • For each neighbor via fetch_outgoing:
      • Compute weight via weight_fn
      • Validate weight.is_finite()
      • new_dist = dist + weight
      • If new_dist <= max_distance AND (not visited OR shorter path):
        • Update distances, enqueue (neighbor, hops + 1)
  3. Extract boundary: nodes where |dist - max_distance| < epsilon
  4. Return result

§Complexity

  • Time: O(|V| + |E|) within the blast zone
  • Space: O(|V|) for distances and blast zone

§Edge Cases

  • Empty graph: Returns {source} with distance 0.0
  • Source not in graph: Returns {source} with distance 0.0
  • Disconnected: Only reaches nodes in source’s component
  • Zero max_distance: Returns {source} only
  • Invalid weights: Returns error if weight_fn returns non-finite value

§Example

use sqlitegraph::{SqliteGraph, algo::observability::{impact_radius, ImpactRadiusConfig, default_weight_fn}};

let graph = SqliteGraph::open_in_memory()?;
// ... build graph ...

// Find all nodes within 3 hops of source
let config = ImpactRadiusConfig {
    max_distance: 3.0,
    max_hops: None,
    weight_fn: &default_weight_fn,
};

let result = impact_radius(&graph, source, &config)?;

println!("Blast zone: {} nodes", result.size);
for &node in &result.blast_zone {
    let dist = result.distances[&node];
    println!("  Node {}: distance {:.2}", node, dist);
}

println!("Boundary: {:?}", result.boundary);