Skip to main content

Cycles

Hydroflow+ supports cyclic graphs, which are useful for iterative computations or patterns like heartbeats.

Because streams are represented as values when constructing a Hydroflow+ graph, we can't directly create cycles since that would require a forward reference. Instead, Hydroflow+ offers an API to create a cycle by using a placeholder stream, which is a stream that can be used as a placeholder for a stream that will be created later.

We can create a cycle by using the cycle method on flow with a process or cluster. This returns a tuple of two values: a HfCycle value that can be used to complete the cycle later and the placeholder stream.

let (complete_cycle, cycle_placeholder) = flow.cycle(&process);

For example, consider the classic graph reachability problem, which computes the nodes reachable from a given set of roots in a directed graph. This can be modeled as an iterative fixpoint computation where we start with the roots, then repeatedly add the children of each node to the set of reachable nodes until we reach a fixpoint.

In Hydroflow+, we can implement this using cycles:

let roots = flow.source_stream(&process, roots);
let edges = flow.source_stream(&process, edges);

let (complete_reached_nodes, reached_nodes) = flow.cycle(&process);

let reach_iteration = roots
.union(&reached_nodes)
.map(q!(|r| (r, ())))
.join(&edges)
.map(q!(|(_from, (_, to))| to));
complete_reached_nodes.complete(&reach_iteration);