Batching and Streaming
Batch Encoding
Use encode_batch when all states are available in memory.
This page fragment is generated from docs/snippets/hgraph_batch.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 ._helpers import first_successor, load_problem, print_encoding_summary
def main() -> None:
space, domain, _problem, state = load_problem("blocks", "smedium")
_action, succ = first_successor(space, state)
encoder = mifrost.HGraphEncoder(domain)
encoding = encoder.encode_batch([state, succ])
print_encoding_summary(
encoding, label="HGraphEncoder.encode_batch([state, successor])"
)
if __name__ == "__main__":
main()
Output
== HGraphEncoder.encode_batch([state, successor]) ==
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": "HGraphEncoder.encode_batch([state, successor])",
"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
Append-Only Stream
Use stream() when samples arrive incrementally and only append semantics are needed.
This page fragment is generated from docs/snippets/hgraph_stream_append_only.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 ._helpers import first_successor, load_problem, print_encoding_summary
def main() -> None:
space, domain, _problem, state = load_problem("blocks", "smedium")
_action, succ = first_successor(space, state)
encoder = mifrost.HGraphEncoder(domain)
stream = encoder.stream()
stream.append(state)
stream.append(succ)
encoding = stream.flush()
print_encoding_summary(
encoding, label="HGraphEncoder.stream().append(...).flush() (2 graphs)"
)
if __name__ == "__main__":
main()
Output
== HGraphEncoder.stream().append(...).flush() (2 graphs) ==
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": "HGraphEncoder.stream().append(...).flush() (2 graphs)",
"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
Flat append-only support:
FlatRelationEncoder.stream()- This stream accepts the same main-lane payloads as
FlatRelationEncoder.encode(...):goals,actions,subgoal_layers,history_subgoals,history_max_steps
Mutable Stream
Use mutable_stream() when you need stable IDs and update/remove semantics.
This page fragment is generated from docs/snippets/hgraph_stream_mutable.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 ._helpers import first_successor, load_problem, print_encoding_summary
def main() -> None:
space, domain, _problem, state = load_problem("blocks", "smedium")
_action, succ = first_successor(space, state)
encoder = mifrost.HGraphEncoder(domain)
mstream = encoder.mutable_stream()
sid0 = mstream.append(state)
sid1 = mstream.append(succ)
mstream.update(sid0, succ)
mstream.remove(sid1)
encoding = mstream.flush()
print_encoding_summary(
encoding,
label="HGraphEncoder.mutable_stream() append/update/remove/flush (1 graph)",
)
if __name__ == "__main__":
main()
Output
== HGraphEncoder.mutable_stream() append/update/remove/flush (1 graph) ==
python: 3.12.13
platform: Linux-6.17.0-1018-azure-x86_64-with-glibc2.39
graph_kind: hetero
num_graphs: 1
num_nodes: 12
num_edges: 24
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": "HGraphEncoder.mutable_stream() append/update/remove/flush (1 graph)",
"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": 24,
"num_graphs": 1,
"num_nodes": 12,
"platform": "Linux-6.17.0-1018-azure-x86_64-with-glibc2.39",
"python": "3.12.13",
"schema_fingerprint": 2869292577121628696
}
SNAPSHOT_JSON_END
Flat mutable support:
FlatRelationEncoder.mutable_stream()FlatHorizonEncoder.stream()FlatTransitionEncoder.stream()FlatTransitionEffectsEncoder.stream()- Flat transition streams are wrapper-level mutable streams built on top of flat horizon streaming.
Semantics
encode_batch(states, *, ...)treatsstatesas the only batch axis.- For batch-capable kwargs, pass either:
- one shared payload (reused for all states), or
- a per-state sequence with
len(...) == len(states)and optionalNoneentries. - Encoder-specific batch kwargs follow the same pattern:
- transition encoders:
successors=successor,successors=[succ0, succ1],successors=BatchParam.shared(successor), orsuccessors=BatchParam.separate([succ0, succ1]) - horizon encoder:
dags=dag,dags=[dag0, None],dags=BatchParam.shared(dag), ordags=BatchParam.separate([dag0, None])where each DAG leaf may be eitherTransitionDAGorrustworkx.PyDiGraph - High-level
encode_batch(...)performs Python-side wrapper/adapter conversion, then executes C++-backed batch parsing. - Low-level
_core._parse_*batch helpers remain strict advanced-only and reject adapter-backed objects. - Example:
- shared:
encoder.encode_batch(states, goals=goals, actions=actions) - per-state:
encoder.encode_batch(states, goals=[g0, g1], actions=[[a0], None]) - transition shared successor:
encoder.encode_batch(states, successors=BatchParam.shared(succ)) - horizon per-entry DAGs:
encoder.encode_batch(states, dags=BatchParam.separate([dag0, None])) rustworkxsupport is optional and stays on the Python side:mifrost.transition_dag_from_rustworkx(...)performs the same conversion explicitly, and directPyDiGraphinputs are normalized toTransitionDAGbefore they reach C++.- Rustworkx candidate metadata import:
- node payload
candidate_id(mapping key or attribute) maps toTransitionDAGnode candidate IDs. - partial candidate IDs fail by default; set
fallback_missing_candidate_id_to_node_index=Trueon explicit conversion to fill gaps. - The interop path assumes the
PyDiGraphis already the correct single-root horizon DAG/tree.mifrostdoes not run a semantic DAG verification pass during conversion. - After conversion, stream and non-stream horizon paths both validate that the DAG root matches the provided root state.
- Horizon/HGraph target rows expose aligned identity metadata:
target_positions[i],target_indices[i], andtarget_candidate_ids[i]refer to the same target row. - Append-only stream intentionally does not provide
update/remove. - Mutable stream provides ID-based mutation and merges cached entries at flush.
- Both stream variants return native
BatchEncodingviaflush(). - Flat
flush_pyg()returnsFlatRelationData, not genericData.