Skip to main content

ModelGraph

A graph: the compiled form of an ONNX model or the recording trace() produces. compile() and trace() return it as built; it is optimized when wanted (optimize()), then finalized (finalize()), then run. run() binds inputs by position or by name and returns the outputs in output_names() order.

device (property)​

The device the graph serves on: the one its compile's weights or to() named, else where its operators sit (the first one's device when they sit on several). A graph with no operators reports the CPU.

__init__​

__init__(self, /, *args, **kwargs)

Initialize self. See help(type(self)) for accurate signature.

add_constant​

add_constantadd_constant(self, tensor: clika_runtime._core.Tensor) -> object

add_constant(self, tensor: clika_runtime._core.Tensor) -> object

add_constant(tensor) -> Value

A new constant holding tensor's bytes (a handle, no copy) that nothing reads yet; set_input() and replace_all_uses_with() take the Value it returns, and constants() lists it. Once an operator reads it, it lives while something reads it, like every constant; finalize() drops it if nothing reads it by then. Raises InvalidArgumentError for a tensor with no data (a traced or a meta tensor).

add_input​

add_inputadd_input(self, spec: clika_runtime._core.TensorSpec) -> object

add_input(self, spec: clika_runtime._core.TensorSpec) -> object

add_input(spec) -> Node

A new graph input named spec.name, last in input_names(), with the dtype and dims of spec: a dynamic dim (-1) takes its size at run(), and dims that share a dim_names entry share that size. Returns its Input node, whose value (output(0)) the other edits take. Raises InvalidArgumentError for an empty name, a name a node carries already, and a dim that is neither positive nor -1.

add_node​

add_nodeadd_node(self, code: clika_runtime._core.graph.OpCode, inputs: object | None, attributes: object | None = None) -> object

add_node(self, code: clika_runtime._core.graph.OpCode, inputs: object | None, attributes: object | None = None) -> object

add_node(code, inputs, attributes=None) -> Node

A new operator of code (an OpCode), built the way its public op builds it, so the op's own checks apply. inputs holds its values, one entry per input port in the op's order: a Value of this graph, or None for an omitted optional operand; trailing entries may be left off, and a constant enters as the Value add_constant() returns. attributes maps the setting names Node.attributes reports to their values: an int also serves a number, an enumerated setting takes its enumerator's name ('Tanh'), a list setting a list of ints, a dtype setting a dtype, and a setting left out takes the op's default. An int past 2**63 - 1 goes in as its 64-bit pattern, which an unsigned setting (a seed) reads back as given. Nothing reads its outputs yet: wire them with set_input(), replace_all_uses_with() or add_output(); finalize() drops a node nothing reads by then, with what only it read. The node is named <OpCode>_<N>, as a trace names it (rename_node() renames it). Raises InvalidArgumentError for a value of another graph or one no longer held, a state buffer, a missing required input or setting, an input or a setting the op does not take, a setting of another kind, the op's own refusal of the arguments, and a code no single public op call builds (an operator with several outputs, one whose public op call takes a setting the operator does not record, or a quantized operator; build those from the public ops that compute them); TypeError for an input that is neither a Value nor None and a setting no op takes (a Tensor, an enumerator object); and OverflowError for an int outside the 64-bit range.

add_output​

add_outputadd_output(self, value: clika_runtime._core.graph.Value, name: str) -> None

add_output(self, value: clika_runtime._core.graph.Value, name: str) -> None

add_output(value, name) -> None

Return value as a new graph output named name, last in output_names(); a value the graph returns already may be returned under a second name. Raises InvalidArgumentError for an empty name, a name another output carries, and a constant or a state buffer (a graph output never returns one directly).

all_simple_edge_paths​

all_simple_edge_pathsall_simple_edge_paths(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, limit: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

all_simple_edge_paths(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, limit: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

all_simple_edge_paths(src, dst, *, cutoff=None, limit=None, avoid=(), edge_filter=None) -> Iterator[list[Edge]]

Every simple path from src to dst, as edges; each parallel edge gives its own path, as networkx's all_simple_edge_paths. src == dst gives one empty path. Depth-first in out_edges() order, with the bounds, the search at the call and the MAX_PATHS_WITHOUT_LIMIT refusal of find_paths_to().

all_simple_paths​

all_simple_pathsall_simple_paths(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, limit: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

all_simple_paths(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, limit: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

all_simple_paths(src, dst, *, cutoff=None, limit=None, avoid=(), edge_filter=None) -> Iterator[list[Node]]

Every simple path from src to dst, as nodes; parallel edges give one path, as networkx's all_simple_paths over the graph with its parallel edges merged. src == dst gives the one-node path. The order, the bounds, the search at the call and the MAX_PATHS_WITHOUT_LIMIT refusal of find_paths_to().

ancestors​

ancestorsancestors(self, node: clika_runtime._core.graph.Node, *, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> list

ancestors(self, node: clika_runtime._core.graph.Node, *, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> list

ancestors(node, *, max_depth=None, max_nodes=None, stop_at=None, edge_filter=None, skip_shape_lane=False) -> list[Node]

Every node with a path to node, node left out, nearest first: a backward walk from it, bounded and filtered as walk() takes them.

bench​

benchbench(self, shapes: collections.abc.Sequence[clika_runtime._core.io.InputShape], options: clika_runtime._core.io.BenchOptions = BenchOptions(warmup=3, iterations=20, fill=FeedFill.Zeros, device=None, reuse_output_buffers=True, batch_axis=None, profile_dir=None)) -> clika_runtime._core.io.BenchReport

bench(self, shapes: collections.abc.Sequence[clika_runtime._core.io.InputShape], options: clika_runtime._core.io.BenchOptions = BenchOptions(warmup=3, iterations=20, fill=FeedFill.Zeros, device=None, reuse_output_buffers=True, batch_axis=None, profile_dir=None)) -> clika_runtime._core.io.BenchReport bench(self, shapes: collections.abc.Sequence[collections.abc.Sequence[int]], options: clika_runtime._core.io.BenchOptions = BenchOptions(warmup=3, iterations=20, fill=FeedFill.Zeros, device=None, reuse_output_buffers=True, batch_axis=None, profile_dir=None)) -> clika_runtime._core.io.BenchReport bench(self, shapes: dict, options: clika_runtime._core.io.BenchOptions = BenchOptions(warmup=3, iterations=20, fill=FeedFill.Zeros, device=None, reuse_output_buffers=True, batch_axis=None, profile_dir=None)) -> clika_runtime._core.io.BenchReport

Overloaded function.

  1. bench(self, shapes: collections.abc.Sequence[clika_runtime._core.io.InputShape], options: clika_runtime._core.io.BenchOptions = BenchOptions(warmup=3, iterations=20, fill=FeedFill.Zeros, device=None, reuse_output_buffers=True, batch_axis=None, profile_dir=None)) -> clika_runtime._core.io.BenchReport

bench(shapes, options=BenchOptions()) -> BenchReport

Time the graph on synthesized inputs of the given shapes: the shapes are validated as validate_shapes() does, one tensor per input is filled per options.fill on the benchmark device, options.warmup untimed runs precede options.iterations timed ones, and the report carries every timed run's milliseconds (each output synchronized before the clock stops), the summary statistics, the process's peak resident set and the device's memory counters. shapes is a list of InputShape, a list of dims in input_names() order, a dict of name to dims, or a dict of name to Tensor (the tensors are fed as they are). InvalidArgumentError on a shape the domains reject; the run's own error when a run fails.

  1. bench(self, shapes: collections.abc.Sequence[collections.abc.Sequence[int]], options: clika_runtime._core.io.BenchOptions = BenchOptions(warmup=3, iterations=20, fill=FeedFill.Zeros, device=None, reuse_output_buffers=True, batch_axis=None, profile_dir=None)) -> clika_runtime._core.io.BenchReport

bench(shapes, options=BenchOptions()) -> BenchReport

The positional form: one dims sequence per input_names() entry, that order.

  1. bench(self, shapes: dict, options: clika_runtime._core.io.BenchOptions = BenchOptions(warmup=3, iterations=20, fill=FeedFill.Zeros, device=None, reuse_output_buffers=True, batch_axis=None, profile_dir=None)) -> clika_runtime._core.io.BenchReport

bench(shapes, options=BenchOptions()) -> BenchReport

The named form: a dict of input name to dims (synthesized inputs), or of input name to Tensor (the caller's tensors, fed as they are; their shapes are still validated).

between​

betweenbetween(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node) -> list

between(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node) -> list

between(src, dst) -> list[Node]

Every node on a path from src to dst, both ends included, in nodes() order; [] when no path runs.

bypass_node​

bypass_nodebypass_node(self, node: clika_runtime._core.graph.Node, input_port: int = 0, output_port: int = 0) -> None

bypass_node(self, node: clika_runtime._core.graph.Node, input_port: int = 0, output_port: int = 0) -> None

bypass_node(node, input_port=0, output_port=0) -> None

Every read of node's output output_port reads the value on its input input_port instead, and node is removed once nothing reads any of its outputs. Raises InvalidArgumentError for an Input node, an input port nothing feeds, an output port nothing reads, a type mismatch between the two values, a node that reads a state buffer, and a constant taking a graph output.

constants​

constantsconstants(self) -> dict

constants(self) -> dict

constants() -> dict[str, Tensor]

The bound constants (weights, baked values) by value name.

consumer_cone​

consumer_coneconsumer_cone(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> list

consumer_cone(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> list

consumer_cone(nodes) -> list[Node]

Every node that reads the outputs of nodes, directly or through others, in nodes() order; the cone of a node no other node reads is [].

count_paths​

count_pathscount_paths(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> int

count_paths(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> int

count_paths(src, dst, *, cutoff=None, avoid=(), edge_filter=None) -> int

How many paths all_simple_paths() lists, counted without listing them, so MAX_PATHS_WITHOUT_LIMIT does not apply. Raises InvalidArgumentError when the count passes 2**64 - 1.

critical_path​

critical_pathcritical_path(self, node_cost: collections.abc.Callable | None = None, edge_cost: collections.abc.Callable | None = None) -> object

critical_path(self, node_cost: collections.abc.Callable | None = None, edge_cost: collections.abc.Callable | None = None) -> object

critical_path(node_cost=None, edge_cost=None) -> WeightedPath

The path of greatest cost: node_cost (a callable taking a Node) summed over its nodes and edge_cost (taking an Edge) over its edges, each finite and of any sign; a cost not given counts 0, so no costs give the path with the most edges. A path may start and end at any node: a prefix whose sum falls below 0 is dropped and the path starts again at the next node, as networkx's dag_longest_path does. Ties go to more edges, then to the path found first. Each cost runs once per node or edge; a NaN or infinite cost raises InvalidArgumentError naming the node or edge.

default_transforms​

default_transformsdefault_transforms(self, defaults: clika_runtime._core.io.DefaultsOptions | None = None) -> list[clika_runtime._core.graph.Transform]

default_transforms(self, defaults: clika_runtime._core.io.DefaultsOptions | None = None) -> list[clika_runtime._core.graph.Transform]

default_transforms(defaults=None) -> list[Transform]

The transform list optimize() runs on this graph under defaults (a DefaultsOptions; None takes every default) when it is handed no list, in the order it runs them: a starting point to edit and hand back as optimize(transforms=...). It follows how the graph was built, so it can differ from the graph-free transforms.defaults(defaults).

depths​

depthsdepths(self) -> dict

depths(self) -> dict

depths() -> dict[Node, int]

Each node's generation: the most edges on a path that ends at it, so depths()[n] is the index of n's layer in layers(). One entry per node, in nodes() order.

descendants​

descendantsdescendants(self, node: clika_runtime._core.graph.Node, *, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> list

descendants(self, node: clika_runtime._core.graph.Node, *, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> list

descendants(node, *, max_depth=None, max_nodes=None, stop_at=None, edge_filter=None, skip_shape_lane=False) -> list[Node]

Every node with a path from node, node left out, nearest first: a forward walk from it, bounded and filtered as walk() takes them.

dominators​

dominatorsdominators(self) -> dict

dominators(self) -> dict

dominators() -> dict[Node, Node]

Each node's immediate dominator: the last node before it that every path from the graph inputs to it crosses. Paths start at the graph inputs, so a constant or weight operand opens none. A node no other node dominates (an input, or a node where two inputs' paths meet) maps to itself, and a node on no path from an input has no entry. Entries in nodes() order.

edges​

edgesedges(self) -> list

edges(self) -> list

edges() -> list[Edge]

Every edge, in (source name, source port, destination name, destination port) order.

edges_between​

edges_betweenedges_between(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node) -> list

edges_between(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node) -> list

edges_between(src, dst) -> list[Edge]

The edges from src to dst, in (source port, destination port) order; [] when no edge runs from one to the other, a node of another graph included. A view whose node an edit removed or renamed raises InvalidArgumentError, as its check() does.

export_onnx​

export_onnxexport_onnx(self, path: object | None, *, opset_version: int = 0, contrib_ops: bool = True, optimize: bool = True, save_as_external_data: bool | None = None, producer_name: str = '') -> None

export_onnx(self, path: object | None, *, opset_version: int = 0, contrib_ops: bool = True, optimize: bool = True, save_as_external_data: bool | None = None, producer_name: str = '') -> None

export_onnx(path, *, opset_version=0, contrib_ops=True, optimize=True, save_as_external_data=None, producer_name='') -> None

Write the graph to path, a str or an os.PathLike, as a runnable ONNX model. The inputs and outputs keep their names, dtypes and dims, and a dynamic dimension is written under its name, so two inputs that share one still share it when the model is read back. The weights become the model's initializers, read one at a time as the file is written, so the export holds no second copy of them. opset_version is the ai.onnx opset the model imports (0 takes the library's default); contrib_ops lets the model use the com.microsoft operators; optimize simplifies the written model (transposes that undo each other compose, and nodes no output reads go); save_as_external_data puts the weights in a '_data' file beside the model: None once they pass 2 GiB, True always and False never; and producer_name is the producer the model records (empty takes the library's). OnnxModel.from_graph() builds the same model in memory, and OnnxModel.open(path).compile() reads the file back. A refusal writes nothing. Raises UnsupportedError for a graph that rewrites a state buffer in place (one given a KV cache by attach_kv_cache(), or traced over a function that writes its cache in place) and for an operator with no ONNX form at the chosen opset, naming the node; InvalidArgumentError for an opset_version the library does not know, and with the code FAILED_PRECONDITION while optimize(), finalize(), attach_kv_cache(), to() or an edit runs on the graph; and TypeError for a path of another type.

finalize​

finalizefinalize(self) -> None

finalize(self) -> None

finalize() -> None

Finalize the graph for serving: place it on the device its compile's weights or to() named (a graph with neither keeps its operators where they are), pack the weights into their kernel layouts, absorb the constants the operators hold, and plan the execution order. A finalized graph runs and refuses optimize(); calling finalize() again changes nothing.

find_cycle​

find_cyclefind_cycle(self) -> list

find_cycle(self) -> list

find_cycle() -> list[Edge]

The edges of one cycle, in order: each edge enters the node the next one leaves, and the last enters the node the first one leaves. [] when the graph has none, as every traced or compiled graph, where networkx's find_cycle() raises.

find_nodes​

find_nodesfind_nodes(self, op_code: clika_runtime._core.graph.OpCode) -> list

find_nodes(self, op_code: clika_runtime._core.graph.OpCode) -> list find_nodes(self, predicate: collections.abc.Callable) -> list

Overloaded function.

  1. find_nodes(self, op_code: clika_runtime._core.graph.OpCode) -> list

find_nodes(op_code) -> list[Node]

Every node running the operator, in name order.

  1. find_nodes(self, predicate: collections.abc.Callable) -> list

find_nodes(predicate) -> list[Node]

Every node predicate accepts, in name order: a callable taking a Node and returning True to accept it. It runs inside the search; an exception it raises ends the search, and find_nodes raises with its message.

find_nodes_by_name​

find_nodes_by_namefind_nodes_by_name(self, pattern: str, match: clika_runtime._core.graph.NameMatch = NameMatch.Whole) -> list

find_nodes_by_name(self, pattern: str, match: clika_runtime._core.graph.NameMatch = NameMatch.Whole) -> list

find_nodes_by_name(pattern, match=NameMatch.Whole) -> list[Node]

Every node whose name the regular expression pattern matches, in name order: the whole name (NameMatch.Whole) or some part of it (NameMatch.Anywhere). The expression syntax is a large PCRE-like subset with no backreferences and no lookaround; a malformed pattern raises InvalidArgumentError with the regex engine's message.

find_paths_to​

find_paths_tofind_paths_to(self, start: clika_runtime._core.graph.Node, target: collections.abc.Callable, *, cutoff: int | None = None, limit: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

find_paths_to(self, start: clika_runtime._core.graph.Node, target: collections.abc.Callable, *, cutoff: int | None = None, limit: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

find_paths_to(start, target, *, cutoff=None, limit=None, avoid=(), edge_filter=None) -> Iterator[list[Node]]

Every simple path from start that ends at the first node target accepts: a path never passes an accepted node, and an accepted start is the one-node path. Depth-first, each node's next nodes in out_edges() order; parallel edges give one path. cutoff is the most edges a path may have, limit the most paths returned (the first ones), avoid the nodes no path may hold (its two ends included), and only the edges edge_filter accepts are taken. The search runs at the call, so its refusals and a callable's exception surface there: without a limit, a search that finds more than MAX_PATHS_WITHOUT_LIMIT paths raises InvalidArgumentError rather than returning a cut list; pass a limit, or count them with count_paths(). The target and the edge filter each run once per node or edge.

find_pattern​

find_patternfind_pattern(self, pattern: clika_runtime._core.graph.Pattern) -> list

find_pattern(self, pattern: clika_runtime._core.graph.Pattern) -> list

find_pattern(pattern) -> list[Match]

Every occurrence of the pattern in this graph, in match order (non-overlapping: a node belongs to at most one occurrence); each Match lists the matched nodes in the pattern's add_node order, None for an absent optional node. A pattern predicate that raises ends the search and the error carries its message.

has_path​

has_pathhas_path(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> bool

has_path(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, cutoff: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> bool

has_path(src, dst, *, cutoff=None, avoid=(), edge_filter=None) -> bool

True when a path runs from src to dst within the bounds find_paths_to() takes; a node reaches itself.

input_names​

input_namesinput_names(self) -> list[str]

input_names(self) -> list[str]

input_names() -> list[str]

Runtime input names, declaration order; the order the positional run() binds.

input_shape_domain​

input_shape_domaininput_shape_domain(self, name: str) -> clika_runtime._core.io.ShapeDomain

input_shape_domain(self, name: str) -> clika_runtime._core.io.ShapeDomain

input_shape_domain(name) -> ShapeDomain

The domain of the input named name; NotFoundError when no input carries it.

inputs​

inputsinputs(self) -> list

inputs(self) -> list

inputs() -> list[tuple[str, DataType, tuple[int, ...]]]

Input slots as (name, dtype, dims) tuples; a dynamic dim reads as -1.

insert​

insertinsert(self, fn: object | None, inputs: object | None) -> list

insert(self, fn: object | None, inputs: object | None) -> list

insert(fn, inputs) -> list[Value]

New operators computed from inputs, a sequence of Values of this graph: the ones fn records when it is traced over one Tensor per input, each with that value's dtype, device and shape (a dynamic dim keeps the graph's own symbol). A constant scalar input goes into fn as the literal it holds, so a value fn reads from it (a range's end, a count) keeps the extent it gives. fn returns a Tensor or a sequence of Tensors, and insert() returns their Values in order, which nothing reads yet: wire them as add_node()'s outputs are wired. A tensor holding data that fn makes or reads becomes a constant of the graph, a value fn returns unchanged comes back as the input it is, and the new nodes take fresh names. fn computes values: it does not write one of its inputs, or a tensor that holds data, in place, and it does not edit this graph or call optimize(). An exception fn raises leaves insert() as that same exception, with the graph as it was. Raises InvalidArgumentError for a value of another graph or one no longer held, a state buffer, a value with no recorded type, such an in-place write, a returned value that holds data, and a read of a tensor without data that is none of its inputs; and TypeError for an fn that cannot be called, an entry that is not a Value, and a return that is not a Tensor or a sequence of Tensors.

is_convex​

is_convexis_convex(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> bool

is_convex(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> bool

is_convex(nodes) -> bool

True when nodes is convex: no path leaves the set and comes back into it, so the set can be cut out and replaced as one piece.

is_finalized​

is_finalizedis_finalized(self) -> bool

is_finalized(self) -> bool

is_finalized() -> bool

True once finalize() ran. compile() and trace() return a graph that is not finalized yet.

is_topological_order​

is_topological_orderis_topological_order(self, order: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> bool

is_topological_order(self, order: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> bool

is_topological_order(order) -> bool

True when order, a sequence of Nodes, is a topological order of this graph: every node exactly once, and every edge running forward. A node of another graph, a repeated or a missing node, or an edge running backward makes it False. A view whose node an edit removed or renamed raises InvalidArgumentError, as its check() does.

kv_cache_info​

kv_cache_infokv_cache_info(self) -> list[clika_runtime._core.io.KVCacheLayerInfo]

kv_cache_info(self) -> list[clika_runtime._core.io.KVCacheLayerInfo]

kv_cache_info() -> list[KVCacheLayerInfo]

The attention layers' KV-cache wiring (past inputs, present outputs, heads, mask family), one entry per layer; empty for a graph without attention.

layers​

layerslayers(self) -> list

layers(self) -> list

layers() -> list[list[Node]]

The topological generations: the nodes with no in-edge first (in_degree() 0), then each node one layer after its latest producer; every layer in nodes() order.

lowest_common_ancestors​

lowest_common_ancestorslowest_common_ancestors(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> list

lowest_common_ancestors(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> list

lowest_common_ancestors(nodes) -> list[Node]

The lowest common ancestors of nodes, a sequence of at least one Node: the nodes every one of them descends from (each counting as its own ancestor) that no other such node descends from, in nodes() order. networkx's lowest_common_ancestor returns one of them.

merge​

mergemerge(self, second: object | None, io_map: collections.abc.Sequence[tuple[str, str]] = []) -> list[clika_runtime._core.graph.Rename]

merge(self, second: object | None, io_map: collections.abc.Sequence[tuple[str, str]] = []) -> list[clika_runtime._core.graph.Rename]

merge(second, io_map=()) -> list[Rename]

Merge second, a ModelGraph, into this graph. Each io_map entry (this_output, second_input) feeds one of this graph's outputs into one of second's inputs; the connected outputs and inputs leave the lists, and everything else stays. The inputs are this graph's, then second's unconnected ones, and the outputs second's, then this graph's unconnected ones. This graph keeps every name, and a name of second's that this graph already uses takes the first free '_'. Returns every name that changed, each under the part 'second' (Rename). The rest is graph.merge()'s: the shapes, the devices, the KV caches and the refusals, the two graphs being the parts 'this' and 'second'. On success second is consumed: it is left empty, and a view of it raises afterwards. A refusal leaves both graphs as they were. Raises InvalidArgumentError for a merge of a graph with itself and graph.merge()'s refusals, with the code FAILED_PRECONDITION inside one of this graph's transforms, and TypeError for a second that is not a ModelGraph.

merge_point​

merge_pointmerge_point(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> object

merge_point(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> object

merge_point(nodes) -> Node | None

Where the paths from nodes, a sequence of at least one Node, merge: the nearest node every path from them to the graph outputs crosses, each counting for itself. None when their paths meet only at the outputs. A node on no path to an output is not counted.

min_value_cut​

min_value_cutmin_value_cut(self, before: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], after: collections.abc.Sequence[clika_runtime._core.graph.Node] = []) -> object

min_value_cut(self, before: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], after: collections.abc.Sequence[clika_runtime._core.graph.Node] = []) -> object

min_value_cut(before=(), after=()) -> ValueCut

The cheapest cut through the graph's values: a split of the nodes in two, every node before the cut with its producers before it, that hands the fewest bytes from the part before to the part after. The graph inputs and the nodes of before run before the cut and the nodes of after after it; a graph output made before the cut is one of the values. A value weighs its tensor's bytes: a view adds nothing to the tensor it re-describes, and a constant or a state buffer is never one of the values. Of the cheapest cuts this is the one nearest the inputs: the least set of nodes before the cut. networkx's minimum_cut returns the one nearest the sink instead; called on the reversed network, from the sink to the source, it returns this one. Raises InvalidArgumentError when no cut exists, naming the node of after that is a graph input, is in before or feeds a node of before, and UnsupportedError when a value has no fixed size in bytes (a dynamic dim), since the cut weighs every value.

node​

nodenode(self, name: str) -> object

node(self, name: str) -> object

node(name) -> Node

The node named name; KeyError when absent.

nodes​

nodesnodes(self) -> list

nodes(self) -> list

nodes() -> list[Node]

Every node in execution order (graph inputs first, then the operators). compile() and trace() return the graph as the model states it; read it there, before optimize() and finalize() rewrite it.

optimize​

optimizeoptimize(self, transforms: collections.abc.Sequence[clika_runtime._core.graph.Transform] | None = None, max_num_iterations: int = 100, *, defaults: clika_runtime._core.io.DefaultsOptions | None = None) -> clika_runtime._core.io.OptimizeReport

optimize(self, transforms: collections.abc.Sequence[clika_runtime._core.graph.Transform] | None = None, max_num_iterations: int = 100, *, defaults: clika_runtime._core.io.DefaultsOptions | None = None) -> clika_runtime._core.io.OptimizeReport

optimize(transforms=None, max_num_iterations=100, *, defaults=None) -> OptimizeReport

Run the graph optimizer: transforms, a list of handles from clika_runtime.graph.transforms run in order each iteration (any of them as often as wanted), iterated until an iteration changes nothing or max_num_iterations (1 to 2147483647) have run. None runs this graph's default list (default_transforms(defaults)); an empty list runs none of them, though the run still drops the nodes nothing reads. defaults is a DefaultsOptions; None takes every default, and the transforms read their settings from it either way. Returns what the run did, one TransformReport per list entry. It runs before finalize(), and raises InvalidArgumentError on a finalized graph, while a run, optimize() or finalize() is in flight on this graph, and before anything runs when the list places a transform ahead of one it must follow or holds a transform that defaults switch off for this graph (each refusal names the list entry and what to change). A transform made from a Python function (Transform) that raises ends the run, and optimize() raises that same exception, with the graph as optimize() found it.

output_names​

output_namesoutput_names(self) -> list[str]

output_names(self) -> list[str]

output_names() -> list[str]

Output names, declaration order; the order run() returns.

outputs​

outputsoutputs(self) -> list

outputs(self) -> list

outputs() -> list[tuple[str, DataType, tuple[int, ...]]]

Output slots as (name, dtype, dims) tuples.

post_dominators​

post_dominatorspost_dominators(self) -> dict

post_dominators(self) -> dict

post_dominators() -> dict[Node, Node]

Each node's immediate post-dominator: the first node after it that every path from it to the graph outputs crosses. A node no other node post-dominates maps to itself, and a node on no path to an output has no entry. Entries in nodes() order.

producer_cone​

producer_coneproducer_cone(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> list

producer_cone(self, nodes: collections.abc.Sequence[clika_runtime._core.graph.Node]) -> list

producer_cone(nodes) -> list[Node]

Every node whose output nodes read, directly or through others, in nodes() order. A node of nodes counts only when another one reads it, so the cone of an input is [].

random_topological_order​

random_topological_orderrandom_topological_order(self, seed: int) -> list

random_topological_order(self, seed: int) -> list

random_topological_order(seed) -> list[Node]

A topological order drawn at random from the valid ones: each node once, after every node whose output it reads. One seed (an integer from 0 to 2**64 - 1) draws one order of a given graph, on every platform.

region​

regionregion(self, entry: clika_runtime._core.graph.Node, exit: clika_runtime._core.graph.Node) -> list

region(self, entry: clika_runtime._core.graph.Node, exit: clika_runtime._core.graph.Node) -> list

region(entry, exit) -> list[Node]

The single-entry, single-exit region from entry to exit: the nodes entry dominates and exit post-dominates, both ends included, in nodes() order; a node alone is a region. Raises InvalidArgumentError, naming the condition that fails, unless entry dominates exit and exit post-dominates entry.

remove_node​

remove_noderemove_node(self, node: clika_runtime._core.graph.Node) -> None

remove_node(self, node: clika_runtime._core.graph.Node) -> None

remove_node(node) -> None

Remove node, an operator nothing reads, with its reads of other values (a constant only it read goes with it). Raises InvalidArgumentError for an Input node and a node that reads a state buffer, and with code_name FAILED_PRECONDITION for a node whose outputs are still read, naming the first reader: rewire or remove that reader first.

remove_output​

remove_outputremove_output(self, name: str) -> None

remove_output(self, name: str) -> None

remove_output(name) -> None

Stop returning the graph output name; the node that computes it stays. Raises InvalidArgumentError for a name no output carries, and with code_name FAILED_PRECONDITION for an output a KV cache layer returns its cache as, naming the layer.

rename_input​

rename_inputrename_input(self, name: str, new_name: str) -> None

rename_input(self, name: str, new_name: str) -> None

rename_input(name, new_name) -> None

Rename the graph input name, and its Input node, new_name. Views of the old name are gone afterwards. Raises InvalidArgumentError for a name no input carries, an empty name and a name a node carries already, and with code_name FAILED_PRECONDITION for an input a KV cache layer reads its cache from, naming the layer.

rename_node​

rename_noderename_node(self, node: clika_runtime._core.graph.Node, name: str) -> None

rename_node(self, node: clika_runtime._core.graph.Node, name: str) -> None

rename_node(node, name) -> None

Name node name; its outputs keep their names. Views of the old name are gone afterwards: find the node again with node(name). Raises InvalidArgumentError for an Input node (rename it with rename_input()), an empty name, and a name another node carries.

rename_output​

rename_outputrename_output(self, name: str, new_name: str) -> None

rename_output(self, name: str, new_name: str) -> None

rename_output(name, new_name) -> None

Rename the graph output name new_name. Raises InvalidArgumentError for a name no output carries, an empty name and a name another output carries, and with code_name FAILED_PRECONDITION for an output a KV cache layer returns its cache as, naming the layer.

replace​

replacereplace(self, old_outputs: object | None, fn: object | None, inputs: object | None) -> list

replace(self, old_outputs: object | None, fn: object | None, inputs: object | None) -> list

replace(old_outputs, fn, inputs) -> list[Value]

insert(fn, inputs), then every read of old_outputs[i] reads new value i, the graph's returns included (they keep their names), and the operators that computed old_outputs from inputs go, with every producer only they read. An operator an input is computed from stays, since the new values read that input; when it makes an old output (an input read from another of its outputs), that output's reads move all the same. Returns the new Values. An exception fn raises leaves replace() as that same exception, with the graph as it was. Raises what insert() raises, and InvalidArgumentError for no old outputs, one listed twice, or one that is a constant, a state buffer or a graph input's value; an old output that is also one of inputs; an old output not computed from inputs; a value those operators make that another node reads or the graph returns (naming it and its reader); a KV cache layer's attention among them; an input computed from a reader of an old output; a count of new values other than the old outputs'; a new value whose type differs from its old output's; and a constant a graph output would return.

replace_all_uses_with​

replace_all_uses_withreplace_all_uses_with(self, old_value: clika_runtime._core.graph.Value, replacement: clika_runtime._core.graph.Value) -> None

replace_all_uses_with(self, old_value: clika_runtime._core.graph.Value, replacement: clika_runtime._core.graph.Value) -> None

replace_all_uses_with(old_value, replacement) -> None

Every read of old_value reads replacement instead: each operator input it feeds, and each graph output it returns (the output keeps its name). Nothing reads old_value afterwards, so its view is gone, unless it is a graph input's value. Raises InvalidArgumentError for replacement being old_value, a type mismatch, a replacement computed from one of old_value's readers (a cycle), a state buffer's reads, a read an operator serves from a weight it holds itself, and a constant taking a graph output.

run​

runrun(self, inputs: collections.abc.Sequence[clika_runtime._core.Tensor]) -> list[clika_runtime._core.Tensor]

run(self, inputs: collections.abc.Sequence[clika_runtime._core.Tensor]) -> list[clika_runtime._core.Tensor] run(self, inputs: dict) -> list[clika_runtime._core.Tensor]

Overloaded function.

  1. run(self, inputs: collections.abc.Sequence[clika_runtime._core.Tensor]) -> list[clika_runtime._core.Tensor]

run(inputs) -> list[Tensor]

Run with positional inputs (input_names() order); returns the outputs in output_names() order.

  1. run(self, inputs: dict) -> list[clika_runtime._core.Tensor]

run(inputs) -> list[Tensor]

Run with named inputs (dict[str, Tensor], strict); returns the outputs in output_names() order.

set_constant_input​

set_constant_inputset_constant_input(self, node: clika_runtime._core.graph.Node, port: int, tensor: clika_runtime._core.Tensor) -> None

set_constant_input(self, node: clika_runtime._core.graph.Node, port: int, tensor: clika_runtime._core.Tensor) -> None

set_constant_input(node, port, tensor) -> None

node's input port reads a new constant holding tensor's bytes: the graph keeps a handle to them, no copy, and finalize() places them with the graph. The constant replaces the value the port reads, so the port already reads one, of the same type. Raises InvalidArgumentError for an Input node, a port nothing feeds, a state buffer's read, a port the operator serves from a weight it holds itself, a tensor with no data (a traced or a meta tensor), and a type mismatch with the value the port reads.

set_input​

set_inputset_input(self, node: clika_runtime._core.graph.Node, port: int, value: clika_runtime._core.graph.Value) -> None

set_input(self, node: clika_runtime._core.graph.Node, port: int, value: clika_runtime._core.graph.Value) -> None

set_input(node, port, value) -> None

node's input port reads value. The edit replaces the value the port reads, so the port already reads one: an input the operator was built without stays empty. Raises InvalidArgumentError for an Input node, a port nothing feeds, a state buffer's read, a port the operator serves from a weight it holds itself, a type mismatch with the value the port reads, and a value computed from node's own outputs (a cycle).

shape_domains​

shape_domainsshape_domains(self) -> list[clika_runtime._core.io.ShapeDomain]

shape_domains(self) -> list[clika_runtime._core.io.ShapeDomain]

shape_domains() -> list[ShapeDomain]

The shapes each input admits, input_names() order: a fixed dimension is Fixed, a dynamic one compiled with a shape spec is Range, any other dynamic one is Free.

shortest_path​

shortest_pathshortest_path(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, edge_cost: collections.abc.Callable | None = None, cutoff: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

shortest_path(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node, *, edge_cost: collections.abc.Callable | None = None, cutoff: int | None = None, avoid: collections.abc.Sequence[clika_runtime._core.graph.Node] = [], edge_filter: collections.abc.Callable | None = None) -> object

shortest_path(src, dst, *, edge_cost=None, cutoff=None, avoid=(), edge_filter=None) -> list[Node] | WeightedPath

Without edge_cost, a path from src to dst with the fewest edges, as its nodes: [src] when the two are one node, [] when no path runs, one answer among equally short paths, the same on every call. With edge_cost, a callable taking an Edge and returning its cost, the cheapest path as a WeightedPath: the costs summed over the edges it takes (among parallel edges, the cheapest), ties to fewer edges, and under cutoff the cheapest path of at most that many edges. Each cost must be finite and at least 0, or InvalidArgumentError names the edge; the cost runs at most once per edge. Unlike networkx, which answers the length through a second function (shortest_path_length), the weighted answer carries its cost. cutoff, avoid and edge_filter bound the search as find_paths_to() takes them.

split_points​

split_pointssplit_points(self) -> list

split_points(self) -> list

split_points() -> list[Node]

The nodes every path from the graph inputs to the graph outputs crosses, from the inputs to the outputs: where the graph splits into two stages at one node. [] when no node is on every such path.

to​

toto(self, where: object) -> None

to(self, where: object) -> None

to(where) -> None

Move the graph to where: a Device, a device string, or a Stream so the graph computes on that stream. Before finalize() it records where finalize() places the graph and moves nothing, and device reports the new device at once. After finalize() it moves the finalized graph: an operator that changes device re-packs its weights there once, and no copy of a moved weight stays behind. A device that cannot serve is refused before anything moves; while a run, optimize(), finalize() or an edit is in flight on this graph it raises InvalidArgumentError, whose code_name is FAILED_PRECONDITION.

to_networkx​

to_networkxto_networkx(self) -> object

to_networkx(self) -> object

to_networkx() -> networkx.MultiDiGraph

The graph as a networkx.MultiDiGraph: one node per Node, keyed by the Node view with its op_code and kind as node data, and one edge per Edge, keyed (src_port, dst_port), so the two reads of Mul(x, x) stay two edges. The networkx graph holds this graph alive through its Node keys. networkx is imported at the call; ImportError when it is not installed.

topological_generations​

topological_generationstopological_generations(self) -> list

topological_generations(self) -> list

topological_generations() -> list[list[Node]]

layers() under networkx's name: the same generations.

topological_order​

topological_ordertopological_order(self, order: clika_runtime._core.graph.TopologicalOrder = TopologicalOrder.Deterministic) -> list

topological_order(self, order: clika_runtime._core.graph.TopologicalOrder = TopologicalOrder.Deterministic) -> list

topological_order(order=TopologicalOrder.Deterministic) -> list[Node]

Every node in the topological order order names: each node once, after every node whose output it reads (see TopologicalOrder for how each kind breaks the ties).

validate_shapes​

validate_shapesvalidate_shapes(self, shapes: collections.abc.Sequence[clika_runtime._core.io.InputShape]) -> None

validate_shapes(self, shapes: collections.abc.Sequence[clika_runtime._core.io.InputShape]) -> None validate_shapes(self, shapes: collections.abc.Sequence[collections.abc.Sequence[int]]) -> None validate_shapes(self, shapes: dict) -> None

Overloaded function.

  1. validate_shapes(self, shapes: collections.abc.Sequence[clika_runtime._core.io.InputShape]) -> None

validate_shapes(shapes) -> None

Check shapes against the domains: every input present once, every name an input, every rank the input's, every extent admitted. shapes is a list of InputShape, a list of dims in input_names() order, or a dict of name to dims. InvalidArgumentError names the input and the dimension that failed.

  1. validate_shapes(self, shapes: collections.abc.Sequence[collections.abc.Sequence[int]]) -> None

validate_shapes(shapes) -> None

The positional form: one dims sequence per input_names() entry, that order.

  1. validate_shapes(self, shapes: dict) -> None

validate_shapes(shapes) -> None

The named form: a dict of input name to dims.

visit​

visitvisit(self, start: clika_runtime._core.graph.Node, visitor: collections.abc.Callable, *, direction: clika_runtime._core.graph.WalkDirection = WalkDirection.Forward, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> None

visit(self, start: clika_runtime._core.graph.Node, visitor: collections.abc.Callable, *, direction: clika_runtime._core.graph.WalkDirection = WalkDirection.Forward, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> None

visit(start, visitor, *, direction=WalkDirection.Forward, max_depth=None, max_nodes=None, stop_at=None, edge_filter=None, skip_shape_lane=False) -> None

The walk walk() takes, showing visitor each node it reaches, the start included. The visitor answers a VisitAction: Prune does not go past that node, and Stop ends the walk, which then returns. None reads as Continue; any other answer ends the walk and raises TypeError. A visitor or callable that raises ends the walk, and visit raises with its message.

visualize​

visualizevisualize(self, path: str) -> None

visualize(self, path: str) -> None

visualize(path) -> None

Write a rendering of the graph's nodes and edges to path (the file suffix picks the format).

walk​

walkwalk(self, start: clika_runtime._core.graph.Node, *, direction: clika_runtime._core.graph.WalkDirection = WalkDirection.Forward, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> list

walk(self, start: clika_runtime._core.graph.Node, *, direction: clika_runtime._core.graph.WalkDirection = WalkDirection.Forward, max_depth: int | None = None, max_nodes: int | None = None, stop_at: collections.abc.Callable | None = None, edge_filter: collections.abc.Callable | None = None, skip_shape_lane: bool = False) -> list

walk(start, *, direction=WalkDirection.Forward, max_depth=None, max_nodes=None, stop_at=None, edge_filter=None, skip_shape_lane=False) -> list[Node]

The nodes a walk from start reaches, in walk order: breadth-first, the start first, each node once at its fewest edges from the start, and a node's neighbors in out_edges() order (in_edges() when direction is Backward). max_depth is the most edges between the start and a node the walk reaches (0 reaches the start alone). max_nodes is the most nodes the walk may reach, the start included: a walk that would reach one more raises InvalidArgumentError naming the budget, never a cut answer. A node stop_at accepts is reached but not gone past (the start included), and the walk crosses only the edges edge_filter accepts. skip_shape_lane crosses no edge that carries shape or index arithmetic (the shape computations the graph optimizer marks; a graph that was not optimized carries no marks). A start of another graph raises InvalidArgumentError; a callable that raises ends the walk, and walk raises with its message.

weakly_connected_components​

weakly_connected_componentsweakly_connected_components(self) -> list

weakly_connected_components(self) -> list

weakly_connected_components() -> list[list[Node]]

The groups of nodes joined by edges taken either way, each in name order, the groups ordered by their first node's name.

would_create_cycle​

would_create_cyclewould_create_cycle(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node) -> bool

would_create_cycle(self, src: clika_runtime._core.graph.Node, dst: clika_runtime._core.graph.Node) -> bool

would_create_cycle(src, dst) -> bool

True when an edge from src to dst would close a cycle: dst reaches src, or the two are one node.