Dynamic Graph Fields
Use dynamic graph fields when you need per-graph attributes collated during native batching.
This is a standalone program and its captured output for this version:
This page fragment is generated from docs/snippets/dynamic_graph_fields.py.
It is intended to show the exact code and typical output for this version.
Commit: 390f8090430944521df7c322996af8aa89f78469
Program
from __future__ import annotations
import mifrost
from mifrost.graph_fields import DType, Mode
from ._helpers import first_successor, load_problem, print_encoding_summary, to_py_list
def main() -> None:
space, domain, _problem, state0 = load_problem("blocks", "smedium")
_action, state1 = first_successor(space, state0)
encoder = mifrost.HGraphEncoder(domain)
enc0 = encoder.encode(state0)
enc1 = encoder.encode(state1)
enc0.goal_distance = 0
enc0.target_indices = [0, 1, 2]
enc1.goal_distance = 1
enc1.target_indices = [0]
batch_enc = mifrost.batch_encodings(
[enc0, enc1],
collate_spec={
"goal_distance": {"mode": Mode.STACK.value, "dtype": DType.F32.value},
"target_indices": {
"mode": Mode.RAGGED_CAT.value,
"dtype": DType.I64.value,
},
},
)
print_encoding_summary(
batch_enc, label="Dynamic attrs via encode + batch_encodings(collate_spec=...)"
)
payload = batch_enc.as_dict()
tensors = payload.get("tensors", {})
print(
"native_graph_field_keys_present:",
sorted(k for k in tensors.keys() if str(k).startswith("__graph__/")),
)
print("goal_distance:", to_py_list(batch_enc.goal_distance, max_items=10))
print("target_indices:", to_py_list(batch_enc.target_indices, max_items=10))
print("target_indices_ptr:", to_py_list(batch_enc.target_indices_ptr, max_items=10))
print("collate_spec:", batch_enc.collate_spec())
if __name__ == "__main__":
main()
Output
== Dynamic attrs via encode + batch_encodings(collate_spec=...) ==
python: 3.12.13
platform: Linux-6.17.0-1018-azure-x86_64-with-glibc2.39
graph_kind: hetero
num_graphs: 2
num_nodes: 24
num_edges: 50
schema_fingerprint: 2869292577121628696
node_types_count: 28
edge_types_count: 54
node_types_head: ['[+]clear[g]', '[+]clear[g][sat]', '[+]handempty[g]', '[+]handempty[g][sat]', '[+]holding[g]', '[+]holding[g][sat]', '[+]on[g]', '[+]on[g][sat]', '[+]ontable[g]', '[+]ontable[g][sat]']
edge_types_head: ['[+]clear[g][sat]|0|_symbol_', '[+]clear[g]|0|_symbol_', '[+]holding[g][sat]|0|_symbol_', '[+]holding[g]|0|_symbol_', '[+]on[g][sat]|0|_symbol_', '[+]on[g][sat]|1|_symbol_', '[+]on[g]|0|_symbol_', '[+]on[g]|1|_symbol_', '[+]ontable[g][sat]|0|_symbol_', '[+]ontable[g]|0|_symbol_']
SNAPSHOT_JSON_BEGIN
{
"edge_types_count": 54,
"edge_types_head": [
"[+]clear[g][sat]|0|_symbol_",
"[+]clear[g]|0|_symbol_",
"[+]holding[g][sat]|0|_symbol_",
"[+]holding[g]|0|_symbol_",
"[+]on[g][sat]|0|_symbol_",
"[+]on[g][sat]|1|_symbol_",
"[+]on[g]|0|_symbol_",
"[+]on[g]|1|_symbol_",
"[+]ontable[g][sat]|0|_symbol_",
"[+]ontable[g]|0|_symbol_"
],
"graph_kind": "hetero",
"label": "Dynamic attrs via encode + batch_encodings(collate_spec=...)",
"node_types_count": 28,
"node_types_head": [
"[+]clear[g]",
"[+]clear[g][sat]",
"[+]handempty[g]",
"[+]handempty[g][sat]",
"[+]holding[g]",
"[+]holding[g][sat]",
"[+]on[g]",
"[+]on[g][sat]",
"[+]ontable[g]",
"[+]ontable[g][sat]"
],
"num_edges": 50,
"num_graphs": 2,
"num_nodes": 24,
"platform": "Linux-6.17.0-1018-azure-x86_64-with-glibc2.39",
"python": "3.12.13",
"schema_fingerprint": 2869292577121628696
}
SNAPSHOT_JSON_END
native_graph_field_keys_present: []
goal_distance: [0.0, 1.0]
target_indices: [0, 1, 2, 0]
target_indices_ptr: [0, 3, 4]
collate_spec: {'goal_distance': {'dtype': 'f32', 'mode': 'stack', 'dim': 1, 'cat_dim': 0, 'inc': {'kind': 'none'}}, 'target_indices': {'dtype': 'i64', 'mode': 'ragged_cat', 'dim': 1, 'cat_dim': 0, 'inc': {'kind': 'none'}}}
Ragged fields expose <attr>_ptr tensors (for example target_indices_ptr) in PyG conversion.
Current Native Behavior
- Native graph fields on
BatchEncodingare accessible as attributes (encoding.goal_distance,encoding.target_indices). - For ragged fields,
<key>_ptris reserved and direct assignment to it is rejected. - In-place mutation on value tensors returned from native access is write-through.
- Ptr tensors are returned as snapshots (mutating the returned ptr tensor does not mutate native storage).
Collision Rules
Python-side graph-field collation specs (dtype="pyobj") may not reuse native graph-field keys.
Attempting to register a colliding key now raises an explicit ValueError.