TrackedDfg#

class hugr.build.tracked_dfg.TrackedDfg(*input_types: Type, track_inputs: bool = False)[source]#

Bases: Dfg

Dfg builder to append operations to wires by index.

Parameters:
  • *input_types – Input types of the Dfg.

  • track_inputs – Whether to track the input wires.

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit, track_inputs=True)
>>> dfg.tracked
[OutPort(Node(1), 0), OutPort(Node(1), 1)]

Methods

add

Add a command to the DFG.

add_alias_defn

Add a type alias definition.

add_cfg

Start building a new CFG nested inside the current dataflow graph.

add_conditional

Start building a new conditional nested inside the current dataflow graph.

add_const

Add a static constant to the graph.

add_if

Start building a new if block nested inside the current dataflow graph.

add_nested

Start building a nested dataflow graph.

add_op

Add a dataflow operation to the graph, wiring in input ports.

add_state_order

Add a state order link between two nodes.

add_tail_loop

Start building a new tail loop nested inside the current dataflow graph.

call

Call a static function in the graph.

define_function

Start building a function definition in the graph.

extend

Add a series of commands to the DFG.

inp

Generate an input port for this node.

inputs

List all incoming wires (output ports of the input node).

insert_cfg

Insert a CFG into the current dataflow graph, wiring in the inputs.

insert_conditional

Insert a conditional into the current dataflow graph, wiring in the inputs.

insert_nested

Insert a nested dataflow graph into the current graph, wiring in the inputs.

insert_tail_loop

Insert a tail loop into the current dataflow graph, wiring in the inputs.

load

Load a constant into the graph as a dataflow value.

load_function

Load a static function into the graph as a higher-order value.

new_nested

Start building a dataflow graph nested inside a larger HUGR.

out

Generate an output port for this node.

out_port

OutPort corresponding to this Wire.

outputs

Returns an iterator over the output ports of this node.

port

Generate a port in direction for this node with offset.

set_indexed_outputs

Set the Dfg outputs, using either Wire or indices to tracked wires.

set_outputs

Set the outputs of the dataflow graph.

set_tracked_outputs

Set the Dfg outputs to the tracked wires.

to_node

Convert to a Node.

track_inputs

Track all input wires and return their indices.

track_wire

Add a wire from this DFG to the tracked wires, and return its index.

track_wires

Set a list of wires to be tracked and return their indices.

tracked_wire

Get the tracked wire at the given index.

untrack_wire

Untrack a wire by index and return it.

Attributes

metadata

Metadata associated with this node.

parent_op

The parent node's operation.

tracked

Tracked wires.

hugr

The Hugr instance that the builder is using.

parent_node

The parent node of the dataflow graph.

input_node

The input node of the dataflow graph.

output_node

The output node of the dataflow graph.

add(com: Command, *, metadata: dict[str, Any] | None = None) Node[source]#

Add a command to the DFG.

Overrides Dfg.add to allow Command inputs to be either Wire or indices to tracked wires.

Any incoming Wire will be connected directly, while any integer will be treated as a reference to the tracked wire at that index.

Any tracked wires will be updated to the output of the new node at the same port as the incoming index.

Parameters:
  • com – Command to append.

  • metadata – Metadata to attach to the function definition. Defaults to None.

Returns:

The new node.

Raises:

IndexError – If any input index is not a tracked wire.

Examples

>>> dfg = TrackedDfg(tys.Bool, track_inputs=True)
>>> dfg.tracked
[OutPort(Node(1), 0)]
>>> dfg.add(ops.Noop()(0))
Node(3)
>>> dfg.tracked
[OutPort(Node(3), 0)]
add_alias_defn(name: str, ty: Type, parent: ToNode | None = None) Node#

Add a type alias definition.

add_cfg(*args: Wire) Cfg#

Start building a new CFG nested inside the current dataflow graph.

Parameters:

args – The input wires to the new CFG.

Returns:

Builder for new nested CFG.

Example

>>> dfg = Dfg(tys.Bool)
>>> with dfg.add_cfg(dfg.inputs()[0]) as cfg:                    cfg.parent_op
CFG(inputs=[Bool])
add_conditional(cond_wire: Wire, *args: Wire) Conditional#

Start building a new conditional nested inside the current dataflow graph.

Parameters:
  • cond_wire – The wire holding the value (of Sum type) to branch the

  • on. (conditional)

  • args – Remaining input wires to the conditional.

Returns:

Builder for new nested conditional.

Example

>>> dfg = Dfg(tys.Bool, tys.Unit)
>>> (cond, unit) = dfg.inputs()
>>> cond = dfg.add_conditional(cond, unit)
>>> cond.parent_node
Node(3)
add_const(value: val.Value, parent: ToNode | None = None) Node#

Add a static constant to the graph.

Parameters:
  • value – The constant value to add.

  • parent – The parent node of the constant. Defaults to the root node.

Returns:

The node holding the Const operation.

Example

>>> dfg = Dfg()
>>> const_n = dfg.add_const(val.TRUE)
>>> dfg.hugr[const_n].op
Const(TRUE)
add_if(cond_wire: Wire, *args: Wire) If#

Start building a new if block nested inside the current dataflow graph.

Parameters:
  • cond_wire – The wire holding the Bool value to branch the If on.

  • args – Remaining input wires to the If (and subsequent Else).

Returns:

Builder for new nested If.

Example

>>> dfg = Dfg(tys.Bool)
>>> (cond,) = dfg.inputs()
>>> if_ = dfg.add_if(cond, cond)
>>> if_.parent_op
Case(inputs=[Bool])
add_nested(*args: Wire) Dfg#

Start building a nested dataflow graph.

Parameters:

args – The input wires to the nested DFG.

Returns:

Builder for new nested dataflow graph.

Example

>>> dfg = Dfg(tys.Bool)
>>> with dfg.add_nested(dfg.inputs()[0]) as dfg2:                   dfg2.parent_node
Node(3)
add_op(op: ops.DataflowOp, /, *args: Wire, metadata: dict[str, Any] | None = None) Node#

Add a dataflow operation to the graph, wiring in input ports.

Parameters:
  • op – The operation to add.

  • args – The input wires to the operation.

  • metadata – Metadata to attach to the function definition. Defaults to None.

Returns:

The node holding the new operation.

Example

>>> dfg = Dfg(tys.Bool)
>>> dfg.add_op(ops.Noop(), dfg.inputs()[0])
Node(3)
add_state_order(src: Node, dst: Node) None#

Add a state order link between two nodes.

Parameters:
  • src – The source node.

  • dst – The destination node.

Examples

>>> df = dfg.Dfg()
>>> df.add_state_order(df.input_node, df.output_node)
>>> list(df.hugr.outgoing_order_links(df.input_node))
[Node(2)]
add_tail_loop(just_inputs: Sequence[Wire], rest: Sequence[Wire]) TailLoop#

Start building a new tail loop nested inside the current dataflow graph.

Parameters:
  • just_inputs – input wires for types that are only inputs to the loop body.

  • rest – input wires for types that are inputs and outputs of the loop

  • body.

Returns:

Builder for new nested TailLoop.

Example

>>> dfg = Dfg(tys.Bool)
>>> (cond,) = dfg.inputs()
>>> tl = dfg.add_tail_loop([cond], [cond])
>>> tl.parent_op
TailLoop(just_inputs=[Bool], rest=[Bool])
call(func: ToNode, *args: Wire, instantiation: tys.FunctionType | None = None, type_args: Sequence[tys.TypeArg] | None = None) Node#

Call a static function in the graph. See Call for more on how polymorphic functions are handled.

Parameters:
  • func – The node corresponding to the function definition/declaration to call.

  • args – The input wires to the function call.

  • instantiation – The concrete function type to call (needed if polymorphic).

  • type_args – The type arguments for the function (needed if

  • polymorphic).

Returns:

The node holding the Call operation.

define_function(name: str, input_types: TypeRow, output_types: TypeRow | None = None, type_params: list[TypeParam] | None = None, parent: ToNode | None = None) Function#

Start building a function definition in the graph.

Parameters:
  • name – The name of the function.

  • input_types – The input types for the function.

  • output_types – The output types for the function. If not provided, it will be inferred after the function is built.

  • type_params – The type parameters for the function, if polymorphic.

  • parent – The parent node of the constant. Defaults to the root node.

Returns:

The new function builder.

extend(*coms: ops.Command) list[Node]#

Add a series of commands to the DFG.

Shorthand for calling add() on each command in coms.

Parameters:

coms – Commands to add.

Returns:

List of the new nodes in the same order as the commands.

Raises:

IndexError – If any input index is not a tracked wire.

Examples

>>> dfg = Dfg(tys.Bool, tys.Unit)
>>> (b, u) = dfg.inputs()
>>> dfg.extend(ops.Noop()(b), ops.Noop()(u))
[Node(3), Node(4)]
hugr: Hugr#

The Hugr instance that the builder is using.

inp(offset: int) InPort#

Generate an input port for this node.

Parameters:

offset – port offset.

Returns:

Incoming port for this node.

Examples

>>> Node(0).inp(1)
InPort(Node(0), 1)
input_node: Node#

The input node of the dataflow graph.

inputs() list[OutPort]#

List all incoming wires (output ports of the input node).

Example

>>> dfg = Dfg(tys.Bool)
>>> dfg.inputs()
[OutPort(Node(1), 0)]
insert_cfg(cfg: Cfg, *args: Wire) Node#

Insert a CFG into the current dataflow graph, wiring in the inputs.

Parameters:
  • cfg – The CFG to insert.

  • args – The input wires to the CFG.

Returns:

The root node of the inserted CFG.

Example

>>> from hugr.cfg import Cfg
>>> dfg = Dfg(tys.Bool)
>>> cfg = Cfg(tys.Bool)
>>> dfg.insert_cfg(cfg, dfg.inputs()[0])
Node(3)
insert_conditional(cond: Conditional, cond_wire: Wire, *args: Wire) Node#

Insert a conditional into the current dataflow graph, wiring in the inputs.

Parameters:
  • cond – The conditional to insert.

  • cond_wire – The wire holding the value (of Sum type) to branch the Conditional on.

  • args – Remaining input wires to the conditional.

Returns:

The root node of the inserted conditional.

Example

>>> from hugr.cond_loop import Conditional
>>> cond = Conditional(tys.Bool, [])
>>> dfg = Dfg(tys.Bool)
>>> cond_n = dfg.insert_conditional(cond, dfg.inputs()[0])
>>> dfg.hugr[cond_n].op
Conditional(sum_ty=Bool, other_inputs=[])
insert_nested(dfg: Dfg, *args: Wire) Node#

Insert a nested dataflow graph into the current graph, wiring in the inputs.

Parameters:
  • dfg – The dataflow graph to insert.

  • args – The input wires to the graph.

Returns:

The root node of the inserted graph.

Example

>>> dfg = Dfg(tys.Bool)
>>> dfg2 = Dfg(tys.Bool)
>>> dfg.insert_nested(dfg2, dfg.inputs()[0])
Node(3)
insert_tail_loop(tl: TailLoop, just_inputs: Sequence[Wire], rest: Sequence[Wire]) Node#

Insert a tail loop into the current dataflow graph, wiring in the inputs.

Parameters:
  • tl – The tail loop to insert.

  • just_inputs – input wires for types that are only inputs to the loop body.

  • rest – input wires for types that are inputs and outputs of the loop

  • body.

Returns:

The root node of the inserted tail loop.

Example

>>> from hugr.cond_loop import TailLoop
>>> tl = TailLoop([tys.Bool], [tys.Bool])
>>> dfg = Dfg(tys.Bool)
>>> (b,) = dfg.inputs()
>>> tl_n = dfg.insert_tail_loop(tl, [b], [b])
>>> dfg.hugr[tl_n].op
TailLoop(just_inputs=[Bool], rest=[Bool])
load(const: ToNode | val.Value, const_parent: ToNode | None = None) Node#

Load a constant into the graph as a dataflow value.

Parameters:
  • const – The constant to load, either a Value that will be added as a child Const node then loaded, or a node corresponding to an existing Const.

  • const_parent – If const is a Value, the parent node for the new constant definition. Defaults to the current dataflow container.

Returns:

The node holding the LoadConst operation.

Example

>>> dfg = Dfg()
>>> const_n = dfg.load(val.TRUE)
>>> len(dfg.hugr) # parent, input, output, const, load
5
>>> dfg.hugr[const_n].op
LoadConst(Bool)
load_function(func: ToNode, instantiation: tys.FunctionType | None = None, type_args: Sequence[tys.TypeArg] | None = None) Node#

Load a static function into the graph as a higher-order value.

Parameters:
  • func – The node corresponding to the function definition/declaration to load.

  • instantiation – The concrete function type to load (needed if polymorphic).

  • type_args – The type arguments for the function (needed if

  • polymorphic).

Returns:

The node holding the LoadFunc operation.

property metadata: dict[str, object]#

Metadata associated with this node.

classmethod new_nested(parent_op: DP, hugr: Hugr, parent: ToNode | None = None) Self#

Start building a dataflow graph nested inside a larger HUGR.

Parameters:
  • parent_op – The parent operation of the new dataflow graph.

  • hugr – The host HUGR instance to build the dataflow graph in.

  • parent – Parent of new dataflow graph’s root node: defaults to the

  • root. (host HUGR)

Example

>>> hugr = Hugr()
>>> dfg = Dfg.new_nested(ops.DFG([]), hugr)
>>> dfg.parent_node
Node(1)
out(offset: int) OutPort#

Generate an output port for this node.

Parameters:

offset – port offset.

Returns:

Outgoing port for this node.

Examples

>>> Node(0).out(1)
OutPort(Node(0), 1)
out_port() OutPort#

OutPort corresponding to this Wire.

output_node: Node#

The output node of the dataflow graph.

outputs() Iterator[OutPort]#

Returns an iterator over the output ports of this node.

parent_node: Node#

The parent node of the dataflow graph.

property parent_op: OpVar#

The parent node’s operation.

port(offset: int, direction: Direction) InPort | OutPort#

Generate a port in direction for this node with offset.

Examples

>>> Node(0).port(1, Direction.INCOMING)
InPort(Node(0), 1)
>>> Node(0).port(1, Direction.OUTGOING)
OutPort(Node(0), 1)
set_indexed_outputs(*in_wires: Wire | int) None[source]#

Set the Dfg outputs, using either Wire or indices to tracked wires.

Parameters:

*in_wires – Wires/indices to set as outputs.

Raises:

IndexError – If any input index is not a tracked wire.

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit)
>>> (b, i) = dfg.inputs()
>>> dfg.track_wire(b)
0
>>> dfg.set_indexed_outputs(0, i)
set_outputs(*outputs: Wire) None#

Set the outputs of the dataflow graph. Connects wires to the output node.

Parameters:

args – Wires to connect to the output node.

Example

>>> dfg = Dfg(tys.Bool)
>>> dfg.set_outputs(dfg.inputs()[0]) # connect input to output
set_tracked_outputs() None[source]#

Set the Dfg outputs to the tracked wires.

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit, track_inputs=True)
>>> dfg.set_tracked_outputs()
to_node() Node#

Convert to a Node.

track_inputs() list[int][source]#

Track all input wires and return their indices.

Returns:

List of indices of the tracked input wires.

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit)
>>> dfg.track_inputs()
[0, 1]
track_wire(wire: Wire) int[source]#

Add a wire from this DFG to the tracked wires, and return its index.

Parameters:

wire – Wire to track.

Returns:

Index of the tracked wire.

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit)
>>> dfg.track_wire(dfg.inputs()[0])
0
track_wires(wires: Iterable[Wire]) list[int][source]#

Set a list of wires to be tracked and return their indices.

Parameters:

wires – Wires to track.

Returns:

List of indices of the tracked wires.

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit)
>>> dfg.track_wires(dfg.inputs())
[0, 1]
tracked: list[Wire | None]#

Tracked wires. None if index is no longer tracked.

tracked_wire(index: int) Wire[source]#

Get the tracked wire at the given index.

Parameters:

index – Index of the tracked wire.

Raises:

IndexError – If the index is not a tracked wire.

Returns:

Tracked wire

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit, track_inputs=True)
>>> dfg.tracked_wire(0) == dfg.inputs()[0]
True
untrack_wire(index: int) Wire[source]#

Untrack a wire by index and return it.

Parameters:

index – Index of the wire to untrack.

Returns:

Wire that was untracked.

Raises:

IndexError – If the index is not a tracked wire.

Examples

>>> dfg = TrackedDfg(tys.Bool, tys.Unit)
>>> w = dfg.inputs()[0]
>>> idx = dfg.track_wire(w)
>>> dfg.untrack_wire(idx) == w
True