Skip to main content

mifrost

mifrost is a high-performance graph encoding library for planning states and transitions. It combines C++ encoder engines (via nanobind) with Python-facing APIs. The API is native-first: encoders return BatchEncoding by default, and PyTorch Geometric (Data / HeteroData) objects are built on demand.

Unit & C++ Tests Install Smoke Wheel Builds Performance Monitor Docs Check

Workflow Platforms Python versions
Unit & C++ Tests macOS, Ubuntu 3.12-3.14
Install Smoke macOS, Ubuntu 3.12-3.14
Wheel Builds macOS, manylinux cibuildwheel cp3.(12-13)
Docs Check Ubuntu 3.12

Documentation

What it does

  • Encodes planning states into graph structures for GNN pipelines.
  • Supports single, batch, and stream-oriented encoding workflows.
  • Exposes multiple encoder families:
    • HGraphEncoder
    • HorizonEncoder
    • TransitionHGraphEncoder / TransitionEffectsHGraphEncoder
    • FlatRelationEncoder, FlatHorizonEncoder, and both flat transition lanes
    • ColorEncoder
    • ILGEncoder
  • Returns native BatchEncoding objects, with explicit helpers for:
    • PyG conversion (encode_pyg, encode_batch_pyg, as_pyg)

Requirements

  • Python >= 3.12
  • A working C++ toolchain
  • At least one optional planner for encoder use: pymimir>=0.13.60 or pytyr==0.0.34
  • For Python-side graph assembly: torch and torch-geometric
  • For source builds: Conan (or CONAN_COMMAND/CONAN_CMD pointing to it)

Python dependency files

  • requirements.txt: runtime Python dependency set
  • requirements/base-build.txt: planner-neutral PEP 517, CMake, and Conan tooling
  • requirements/build.txt: Python tooling for source builds (conan, cmake, ninja, etc.)
  • requirements/test.txt: test-only Python dependencies
  • requirements/perf.txt: performance-gate dependencies
  • requirements/dev.txt: convenience union of build + test + perf + quality tools
  • requirements/constraints-ci.txt: CI-only version constraints used by workflows
  • pyproject.toml backend extras: .[pymimir], .[pytyr], .[backends]
  • Development extras: .[test], .[perf], .[dev]

Installation

From PyPI

pip install "mifrost[pymimir]"

For PyTyr instead, or to use both planners in the same process:

pip install "mifrost[pytyr]"
pip install "mifrost[backends]"

From source (wheel)

git clone https://github.com/maichmueller/mifrost.git
cd mifrost
pip install ".[pymimir]"

Source builds contain both adapter modules by default. Set MIFROST_BUILD_BACKENDS=core, pymimir, pytyr, or both to build an explicit subset; for example:

MIFROST_BUILD_BACKENDS=pytyr pip install ".[pytyr]"

If Conan is not on your PATH, set:

export CONAN_COMMAND=/path/to/conan

If pymimir is installed but CMake cannot locate it, set:

export MIFROST_MIMIR_CMAKE_DIR="$(python -c 'import pymimir; print(pymimir.get_cmake_dir())')"

Editable install (development)

python -m pip install --no-build-isolation \
  --config-settings=editable.rebuild=true \
  -Cbuild-dir=build_editable \
  -e .

This enables import-triggered rebuild behavior from scikit-build-core for local development.

Reusable C++ SDK from the installed package

Installed wheels also ship the reusable native SDK alongside the Python module:

python -c 'import mifrost; print(mifrost.get_include_dir())'
python -c 'import mifrost; print(mifrost.get_cmake_dir())'
python -c 'import mifrost; print(mifrost.get_library_dir())'

Use mifrost.get_cmake_dir() in downstream CMake projects to extend CMAKE_PREFIX_PATH or pass -Dmifrost_DIR="$(python -c 'import mifrost; print(mifrost.get_cmake_dir())')".

Quick start (native-first)

import mifrost

# Pymimir domains and PyTyr planning tasks select their backend per instance.
encoder = mifrost.HGraphEncoder(domain_or_planning_task)

# state: a matching Pymimir or PyTyr state
encoding = encoder.encode(state)         # BatchEncoding
data = encoding.as_pyg()                 # HeteroData

batch_encoding = encoder.encode_batch([state1, state2, state3])  # BatchEncoding
batch = batch_encoding.as_pyg(as_batch=True)                     # HeteroDataBatch

# explicit PyG convenience helpers
data2 = encoder.encode_pyg(state)
batch2 = encoder.encode_batch_pyg([state1, state2, state3])
encoding_dict = batch_encoding.as_dict()      # dictionary form
# note: encoding_dict["tensors"] entries are DLPack-exporting values
# (consume with torch.utils.dlpack.from_dlpack(...) or mifrost.encoding_to_tensors(...))

Every public encoder family supports backend="pymimir" or backend="pytyr" for explicit selection; omitting it infers the backend from the constructor input. Instances from both planners can safely coexist. Their compatible outputs are ordinary planner-free BatchEncoding values and can be batched together:

pymimir_encoder = mifrost.HGraphEncoder(pymimir_domain)
pytyr_encoder = mifrost.HGraphEncoder(pytyr_planning_task)

mixed = mifrost.batch_encodings(
    [
        pymimir_encoder.encode(pymimir_state),
        pytyr_encoder.encode(pytyr_state),
    ],
    fast_path=True,
)
assert mixed.num_graphs == 2

See examples/encoders/backend_interchangeability_example.py for a complete same-process example that parses both planners, creates one mixed PyG batch, and runs a Torch forward/backward step.

Example output (trimmed):

type(encoding): BatchEncoding
type(data): HeteroData
node_type_count: 28
node_types_head:
  ['[+]on[g]', '_symbol_', 'clear', 'object', 'ontable',
   '[+]clear[g]', '[+]clear[g][sat]', '[+]handempty[g]']
edge_type_count: 54

type(batch_encoding): BatchEncoding
type(batch): HeteroDataBatch
num_graphs: 3
node_type_count: 28

encoding keys:
  ['node_feature_dims', 'node_names', 'num_graphs', 'object_names', 'schema', 'tensors']
schema keys:
  ['edge_tensors', 'edge_types', 'extensions', 'flags', 'graph_kind',
   'node_tensors', 'node_types', 'version']
tensor_count: 164
tensor_keys_head:
  ['_symbol_|0|object/edge_index_0', '_symbol_|0|object/edge_index_1',
   'object|0|_symbol_/edge_index_0', 'object|0|_symbol_/edge_index_1', ...]

Stream workflow:

stream = encoder.stream()
stream.append(state1)
stream.append(state2)

batch_encoding = stream.flush()  # BatchEncoding
batch = batch_encoding.as_pyg(as_batch=True)    # HeteroDataBatch

# convenience
batch2 = stream.flush_pyg(as_batch=True)

# mutable stream (supports update/remove)
mutable = encoder.mutable_stream()
sid = mutable.append(state1)
mutable.update(sid, state2)
mutable.remove(sid)

Example output:

type(batch): HeteroDataBatch
num_graphs: 2
node_type_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]']

Encoding quick lookup

C++ (HGraphEncoderEngine)

All methods append into an existing BatchBuilder (they do not clear it). Call builder.next_graph() to commit one graph.

  • encode(state, builder) / encode_state(state, builder)

    • State-only graph (objects + current facts).
  • encode_step<GoalTag>(state, goals_span, actions_span, builder)

    • Convenience overload for typed goal literals (wraps into GoalInputs internally).
  • encode(state, goals: GoalInputs, actions_span, builder)

    • Full step graph (state + goals + optional actions; plus optional derived relations depending on config).
  • encode(state, goals, actions_span, history_subgoals, history_max_steps, builder)

    • Full step graph plus history nodes/links (dt-tagged subgoals).

C++ streaming

  • HGraphStreamEncoder (append-only)

    • Direct append into one persistent builder.
    • append(...) -> id, flush(), flush_pyg(), reset().
  • HGraphMutableStreamEncoder (cached/mutable, via StreamEncoderBase)

    • Supports update/remove with id stability and cache merge on flush.
    • append(...) -> id, update(id, ...), remove(id), flush(), flush_pyg(), reset(), set_reuse_removed(bool).

Python (HGraphEncoder)

  • encode(state, *, ...) -> BatchEncoding

    • One graph, native encoding object.
  • encode_pyg(state, *, ...) -> HeteroData

    • One graph, explicit PyG conversion path.
  • encode_batch(states, *, ...) -> BatchEncoding

    • Many graphs, native batch encoding object.
  • encode_batch_pyg(states, *, ...) -> HeteroDataBatch

    • Many graphs, explicit PyG conversion path.
  • encode_batch argument semantics

    • states is always the batch axis.

    • Each extra batch argument is either shared (applies to all states) or a per-state sequence of length len(states) with optional None entries.

    • Batch parsing/execution is C++-backed across encoders.

    • High-level encode_batch(...) accepts wrapper/native planning inputs and converts wrapper/adapter-backed values in Python before entering the C++ batch parser.

    • Low-level _core._parse_* helpers and C++ batch internals are strict advanced-only.

    • Unknown batch kwargs raise TypeError; family-specific unsupported lanes raise a descriptive ValueError when they contain values.

    • Per-state argument length mismatches raise ValueError.

    • Example:

      • Shared goals/actions:
        • encoder.encode_batch(states, goals=goals, actions=actions)
      • Per-state goals/actions:
        • encoder.encode_batch(states, goals=[goals0, goals1], actions=[[a0], None])
    • Migration notes (hard break):

      • Old encoder-specific inference/ignoring of batch kwargs was removed.
      • Low-level _core._parse_* batch parser helpers no longer accept adapter-backed custom Python types.
        • High-level encoder encode_batch(...) now performs Python-side adapter conversion.
      • Transition*Encoder requires aligned successors and rejects explicit action/history lanes.
      • HorizonEncoder accepts per-state dags/goals/subgoal_layers and rejects explicit action/history lanes.
      • ColorEncoder rejects action payloads.
  • stream() -> HGraphEncoderStream

    • Create an append-only stream encoder backed by the same C++ engine.
  • mutable_stream() -> HGraphMutableEncoderStream

    • Create a mutable stream encoder supporting update/remove.

Python streaming (HGraphEncoderStream, append-only)

  • append(state, *, goals=None, actions=None, subgoal_layers=None, history_subgoals=None, history_max_steps=None) -> id
  • flush() -> BatchEncoding
  • flush_pyg(...) -> PyG

Python mutable streaming (HGraphMutableEncoderStream)

Cached stream wrapper (ids + edits), merges on flush.

  • append(state, *, goals=None, actions=None, subgoal_layers=None, history_subgoals=None, history_max_steps=None) -> id
  • update(id, state, *, ...)
  • remove(id)
  • flush() -> BatchEncoding
  • flush_pyg(...) -> PyG

Extending input types (adapter API)

Encoders are strict for native pymimir (advanced) types, but you can register explicit adapters for custom wrappers:

import mifrost

mifrost.register_state_adapter(MyStateType, lambda s: s.to_advanced_state())
mifrost.register_domain_adapter(MyDomainType, lambda d: d.to_advanced_domain())
mifrost.register_literal_adapter(MyLiteralType, lambda l: l.to_advanced_literal())
mifrost.register_action_adapter(MyActionType, lambda a: a.to_advanced_action())

Adapters are matched by exact concrete type.

Batch hard-break note:

  • High-level encode_batch(...) / encode_batch_pyg(...) use adapter registries during Python-side preprocessing before calling strict C++ batch parsing.
  • Direct low-level _core._parse_* batch helper calls remain advanced-only and reject adapter-backed objects.

Development

Configure and build C++ targets

python configure.py --config Release
python cbuild.py

Or use CMake presets:

cmake --preset local-release
cmake --build build/local-release

Build benchmarks:

python configure.py --config Release --build_dir build/bench-release --with_benchmarks
python cbuild.py build/bench-release --bench

Batch collation microbenchmark (batch_encodings, including pyobj collation):

python scripts/benchmark_batch_encodings.py --repeats 400 --warmup 50

Tests

Python tests:

pytest -q

C++ tests (after configure/build):

./build/<...>/src/mifrost_tests

Profiling

python scripts/profile_encoding.py --domain blocks --problem small
python scripts/profile_encoding.py --profile cprofile --include-goals
python scripts/profile_encoding.py --benchmark-pyg --no-export-node-names

Comprehensive scaling benchmark suite (diverse state batches, goals/actions combinations, transition encoders, horizon DAG-size sweeps):

python scripts/benchmark_encoder_suite.py \
  --domain blocks \
  --problem smedium \
  --max-states 256 \
  --batch-sizes 8,32,128 \
  --horizon-dag-sizes 8,32,64 \
  --horizon-batch-sizes 4,16 \
  --include-lgan-values false,true \
  --repeats 5 \
  --warmup 1 \
  --output-json /tmp/encoder_bench_suite.json

Include PyG conversion paths in the same run:

python scripts/benchmark_encoder_suite.py --benchmark-pyg

Output assembly notes

  • Native-first:
    • encode(...) / encode_batch(...) return BatchEncoding.
    • BatchEncoding.as_pyg(...) converts to PyG.
  • Convenience:
    • encode_pyg(...) / encode_batch_pyg(...) return PyG directly.
  • BatchEncoding supports as_dict(), schema_fingerprint(), save(...), load(...).
  • mifrost.batch_encodings([...]) batches single-graph encodings natively with schema checks.
  • Use mifrost.encoding_to_tensors(encoding.as_dict()) when feeding a custom downstream pipeline.

Encoder architecture note

  • See docs/development/architecture.md for the current Python/native layout and encoder architecture notes.

License

GPL-3.0-only

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mifrost-0.5.0.tar.gz (714.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

mifrost-0.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (10.7 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

mifrost-0.5.0-cp313-cp313-macosx_11_0_arm64.whl (7.1 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

mifrost-0.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (10.7 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

mifrost-0.5.0-cp312-cp312-macosx_11_0_arm64.whl (7.1 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file mifrost-0.5.0.tar.gz.

File metadata

  • Download URL: mifrost-0.5.0.tar.gz
  • Upload date:
  • Size: 714.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for mifrost-0.5.0.tar.gz
Algorithm Hash digest
SHA256 e6d4567c6797c3a18ba46650270cb938f1e62c2754416bf9221ba045a2e48961
MD5 d1be64b313b8f849dc53e717b779b420
BLAKE2b-256 0822583c6db57be421682b5763f4f5c6e7a436fab6da9214e8a5654b69329ea1

See more details on using hashes here.

Provenance

The following attestation bundles were made for mifrost-0.5.0.tar.gz:

Publisher: wheels.yml on maichmueller/mifrost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mifrost-0.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for mifrost-0.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 5dafa83e755d855b971676ac3daada79bfad0c1eeb11f34e6f5c500744b1dbcd
MD5 a154ea41c6d5f4c03aed65cb80d62d42
BLAKE2b-256 f39c942e7dbb18943390d0c42d951c2c45ea2615eb2e26b1a38d4cf815572027

See more details on using hashes here.

Provenance

The following attestation bundles were made for mifrost-0.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on maichmueller/mifrost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mifrost-0.5.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mifrost-0.5.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 160d3edfe41ab42b769bc3cbfb740d1cbff0232f6cf778b54c2f6c82f6bafe6c
MD5 07c0d90d49bdfdb7c96ebda33ecd82ca
BLAKE2b-256 08204f2d8b228ea5b75a55d6e2c4d20efbaa1a8353b2247d96d12f58e7cd4def

See more details on using hashes here.

Provenance

The following attestation bundles were made for mifrost-0.5.0-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: wheels.yml on maichmueller/mifrost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mifrost-0.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for mifrost-0.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6861ddad8260d70942b91d47e09c6cc2c3dfd74adff5ca9cfcb0cfbcd8f7e0bf
MD5 03d87bba1ca031808c8d80a4e1c55f8b
BLAKE2b-256 8683a1cb455a3b0683e7cd546149ea7f248b32eca9f4f57e00e5c84e1ad02d0a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mifrost-0.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on maichmueller/mifrost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mifrost-0.5.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mifrost-0.5.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 457ca27cc3bfd2a9d7c5096569036ba020f979f4699848698feb6b112433d185
MD5 bb9977a7114148c36b9d90f3febb5df9
BLAKE2b-256 fe6d569524590cc66f1dd5b4993f0589b0e4c186bf1491e90357291bde4ffa6a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mifrost-0.5.0-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: wheels.yml on maichmueller/mifrost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.5.0 This release

5 files

0.4.0

5 files

0.3.1

16 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page