problem_to_str : Problem -> Str
Explain one validation problem in plain language. Numbers identify zero-based positions or referenced values as stated in each message.
:= []
Directed graph layout read as flow.
layout is the usual entry point. For repeated layouts of unchanged input,
call prepare once and pass the result to layout_prepared. For small,
important drawings, layout_exact searches for the layer orderings with
the fewest edge crossings under an explicit effort cap and reports whether
optimality was proven.
problem_to_str : Problem -> Str
Explain one validation problem in plain language. Numbers identify zero-based positions or referenced values as stated in each message.
default_input : Input
Empty flow input. Replace graph by record update.
default_settings : Settings
Settings that produce a readable top-to-bottom layout in common cases.
default_run : RunArgs
Reflow for best layout quality without previous-position hints.
Check the input and settings, then cache work reusable across layouts.
layout_prepared : Prepared, RunArgs -> Result
Lay out previously prepared input. This operation cannot fail.
Check and lay out input in one call. This is the usual entry point.
default_exact_settings : ExactSettings
Default spacing and routing with an effort cap of 100,000 ordering choices — enough to prove optimality for small drawings.
prepare_exact : Input, ExactSettings -> [Ok(ExactPrepared), Err(List(Problem))]
Check the input and settings, run the crossing search, and cache the chosen ordering with everything else reusable across layouts.
layout_exact_prepared : ExactPrepared -> ExactResult
Lay out previously prepared exact input. This operation cannot fail.
layout_exact : Input, ExactSettings -> [Ok(ExactResult), Err(List(Problem))]
Check and lay out input with the fewest edge crossings the effort cap
allows, in one call. Direction handling, layer assignment, spacing,
and routes are exactly as in layout; only the ordering of nodes
within each layer differs, chosen by exhaustive search rather than
heuristic sweeps. The search cost grows steeply with layer width, so
the effort cap bounds it: at the cap the best ordering found — never
worse than layout's — is returned with proven_optimal: False.
LayerConstraint : [SameLayer({ first : U64, second : U64 }), BeforeLayer({ first : U64, second : U64, minimum_span : U64 }), FirstLayer(U64), LastLayer(U64)]
Hard relationships between node layers. BeforeLayer follows the
selected flow direction, so it has the same meaning for every direction.
Input : {
graph : {
nodes : List({ width : F64, height : F64 }),
edges : List({ from : U64, to : U64 }),
},
edge_weights : List({ edge : U64, weight : F64 }),
min_spans : List({ edge : U64, span : U64 }),
attachments : List(AttachmentRule),
boundaries : List(BoundaryRule),
edge_labels : List(EdgeLabel),
layer_constraints : List(LayerConstraint),
order_constraints : List({ before : U64, after : U64 }),
non_ranking_edges : List(U64),
}
Directed flow input. Edge identity is its index. Most callers only set
graph; the sparse lists add labels, endpoint geometry, or authored
placement. Layer constraints describe flow-relative rows, order
constraints arrange nodes that share a row, and non-ranking edges are
routed without influencing rows or cycle breaking. In an order
constraint, before means visually left of after for vertical flow and
visually above it for horizontal flow, regardless of direction.
Settings : { node_gap : F64, layer_gap : F64, routing : Settings, direction : [Down, Up, Left, Right], max_sweeps : U64, pins : List({ node : U64, x : F64, y : F64 }) }
Space between nodes on the same layer and between adjacent layers, plus orthogonal routing clearance, edge separation, and path preferences. Every edge is routed after placement against all node boxes. Sparse pins hold node centers exactly; preparation reports pins that cannot coexist with strict layer alignment and configured gaps.
Per-layout choices. Hints are sparse and addressed by node index; invalid
run-time entries are ignored and the final valid duplicate wins.
PreserveOrder keeps the mutual within-layer order of hinted nodes while
allowing unhinted nodes to be inserted. Authored constraints take priority.
Problem : [
InvalidNodeWidth(U64),
InvalidNodeHeight(U64),
MissingEdgeStart(U64, U64),
MissingEdgeEnd(U64, U64),
InvalidNodeGap,
InvalidLayerGap,
MissingEdgeWeightEdge(U64),
InvalidEdgeWeight(U64),
NonRankingEdgeWeight(U64, U64),
MissingMinimumSpanEdge(U64),
InvalidMinimumSpan(U64),
NonRankingMinimumSpan(U64, U64),
InvalidAttachmentEdge(U64),
InvalidAttachmentOffset(U64),
DuplicateAttachment(U64),
InvalidBoundaryNode(U64),
DuplicateBoundary(U64),
MissingPinNode(U64, U64),
InvalidPin(U64),
DuplicatePin(U64),
ConflictingPins,
InvalidEdgeLabelEdge(U64),
InvalidEdgeLabelWidth(U64),
InvalidEdgeLabelHeight(U64),
MissingLayerConstraintNode(U64, U64),
InvalidLayerConstraintSpan(U64),
ConflictingLayerConstraints,
MissingOrderConstraintNode(U64, U64),
OrderConstraintAcrossLayers(U64),
ConflictingOrderConstraints,
MissingNonRankingEdge(U64, U64),
DuplicateNonRankingEdge(U64),
InvalidRouting(Problem),
]
Invalid sizes, spacing, references, or authored relationships found while
checking input. NonRankingEdgeWeight and
NonRankingMinimumSpan report the sparse setting index followed by its
edge index.
Result : {
layout : {
positions : List({ x : F64, y : F64 }),
bounds : { x : F64, y : F64, width : F64, height : F64 },
routes : List(Route),
},
layers : List(U64),
backward_edges : List(U64),
label_anchors : List({ x : F64, y : F64 }),
attachments : List(EdgeAttachments),
}
Geometry plus each node's layer and any edges drawn against the flow. Positions hold node centers; route endpoints lie on the source and target node boundaries.
ExactSettings : { node_gap : F64, layer_gap : F64, routing : Settings, effort_cap : U64, direction : [Down, Up, Left, Right], pins : List({ node : U64, x : F64, y : F64 }) }
Settings for layout_exact: spacing and routing exactly as in
Settings, plus effort_cap — the most ordering choices the crossing
search may try before stopping with the best ordering found so far.
Higher caps prove optimality on wider layers at higher cost; a cap of
zero still returns a deterministic best-known order. Pins have the same
exact-coordinate and preparation-conflict behavior as Settings.
0 skips the search entirely and keeps the ordering layout would
produce.
ExactResult : {
layout : {
positions : List({ x : F64, y : F64 }),
bounds : { x : F64, y : F64, width : F64, height : F64 },
routes : List(Route),
},
layers : List(U64),
backward_edges : List(U64),
proven_optimal : Bool,
label_anchors : List({ x : F64, y : F64 }),
attachments : List(EdgeAttachments),
}
Everything Result reports, plus whether the crossing search proved
its ordering has the fewest crossings any ordering can achieve:
True when the search finished within the effort cap or the ordering
is crossing-free, False when the cap stopped the search early or hard
ordering rules were applied after the unconstrained search.