weavatrix-graph 0.2.0

Deterministic, evidence-carrying graph primitives for repository intelligence
Documentation
use crate::IndexGraphView;
use std::collections::VecDeque;

pub(super) fn indexed_nodes<G: IndexGraphView>(graph: &G) -> Vec<Option<G::Node>> {
    let mut nodes = vec![None; graph.node_bound()];
    for node in graph.node_indices() {
        nodes[G::node_slot(node)] = Some(node);
    }
    nodes
}

pub(super) fn residual_reachable<G>(
    graph: &G,
    source: G::Node,
    capacities: &[u64],
    flows: &[u64],
) -> Vec<bool>
where
    G: IndexGraphView,
{
    let nodes = indexed_nodes(graph);
    let mut seen = vec![false; graph.node_bound()];
    let source = G::node_slot(source);
    seen[source] = true;
    let mut queue = VecDeque::from([source]);
    while let Some(node) = queue.pop_front() {
        let Some(node_key) = nodes[node] else {
            continue;
        };
        for edge in graph.outgoing_edges(node_key) {
            let slot = G::edge_slot(edge);
            if capacities[slot] > flows[slot]
                && let Some(target) = graph.edge_endpoints(edge).map(|e| G::node_slot(e.target()))
            {
                push_unseen(target, &mut seen, &mut queue);
            }
        }
        for edge in graph.incoming_edges(node_key) {
            if flows[G::edge_slot(edge)] > 0
                && let Some(target) = graph.edge_endpoints(edge).map(|e| G::node_slot(e.source()))
            {
                push_unseen(target, &mut seen, &mut queue);
            }
        }
    }
    seen
}

fn push_unseen(node: usize, seen: &mut [bool], queue: &mut VecDeque<usize>) {
    if !seen[node] {
        seen[node] = true;
        queue.push_back(node);
    }
}