MimirWorkflows.Graph (mimir_workflows v0.7.0)

Copy Markdown View Source

Pure directed-graph algorithms over an edge list of {upstream, downstream} pairs.

Nodes may be any term. Adjacency, reachability and cycle detection use exact map/set identity, so 1 and 1.0 are distinct nodes. strictly_upstream?/3 first excludes nodes equal under ==, including numerically equal integers and floats, then checks exact reachability.

Summary

Functions

Forward adjacency map (upstream => [downstream]) built from an edge list. Downstreams accumulate in reverse insertion order, which no consumer depends on.

True if the edge list contains a directed cycle.

Every node reachable from start following forward edges, including start itself.

True if there is a directed path target → … → node with target != node.

Types

adjacency()

@type adjacency() :: %{required(node_id()) => [node_id()]}

edge()

@type edge() :: {node_id(), node_id()}

node_id()

@type node_id() :: term()

Functions

adjacency(edges)

@spec adjacency([edge()]) :: adjacency()

Forward adjacency map (upstream => [downstream]) built from an edge list. Downstreams accumulate in reverse insertion order, which no consumer depends on.

has_cycle?(edges)

@spec has_cycle?([edge()]) :: boolean()

True if the edge list contains a directed cycle.

Standard DFS: visiting is the current DFS stack (a back-edge into it is a cycle); visited is nodes whose subtrees have been fully explored and proven cycle-free. Threading visited across DFS roots keeps the walk linear in node + edge count instead of exponential on DAGs with shared descendants.

reachable_from(start, edges)

@spec reachable_from(node_id(), [edge()]) :: MapSet.t()

Every node reachable from start following forward edges, including start itself.

strictly_upstream?(target, node, edges)

@spec strictly_upstream?(node_id(), node_id(), [edge()]) :: boolean()

True if there is a directed path target → … → node with target != node.