Skip to content

Architecture

The repository separates concerns between a fast Rust core and a flexible Python orchestration layer. Python assembles prompts, communicates with local models, cleans and validates outputs, and runs evaluation pipelines. Rust provides the deterministic environment, ideal abstractions, and a simulator that can execute either in the ground MDP or over an abstract state space. This separation keeps experiments both reproducible and quick while making it easy to iterate on prompts and analysis in Python.

At a glance, the Python layer contains the prompt builder, the LLM client and post‑processor, the bisimulation‑style scorer, and the MCTS runners and analysis tools. The Rust core implements the gridworld, homomorphism routines for ideal abstractions, utilities to build transition and reward matrices, and the stateless simulator exposed to Python via pyo3. The short overview below names the most relevant modules on each side; the component diagram in Figure 1 illustrates how they connect.

Overview - Rust core (src/core). The game module defines Game and a fast stateless simulator; abstraction exposes get_all_states and get_abstraction to support matrix construction; runner hosts MCTS search that Python calls through PyRunner. - Python layer (llm_abstraction/). llm.prompts.generate_prompts assembles prompts; llm.ollama.query_llm queries local models; llm.clean normalises responses; llm.scoring.bisimulation_similarity compares clusterings; evaluation modules run MCTS via the Rust extension.

Key entry points - CLI: main.py defines subcommands. - Prompt builder: llm_abstraction.llm.prompts.generate_prompts. - LLM client: llm_abstraction.llm.ollama.query_llm (wraps ollama.chat). - Cleaner: llm_abstraction.llm.clean.clean_with_regex_and_validate. - Scorer: llm_abstraction.llm.scoring.bisimulation_similarity. - Runners: llm_abstraction.evaluation.mcts.run_mcts, run_mcts_llm. - Rust bindings: core_rust module in src/lib.rs (e.g., PyRunner, generate_mdp).

flowchart LR
  subgraph Python Layer
    CLI["CLI (main.py)"]
    PB["llm_abstraction.llm.prompts.generate_prompts"]
    LLM["llm_abstraction.llm.ollama.query_llm (Ollama)"]
    CLEAN["llm_abstraction.llm.clean.clean_with_regex_and_validate"]
    SCORE["llm_abstraction.llm.scoring.bisimulation_similarity"]
    RUN["llm_abstraction.evaluation.mcts.run_mcts / run_mcts_llm"]
  end
  subgraph Rust Core
    WORLD["core::game::game_logic::Game"]
    HOMO["core::abstraction::homomorphism::get_abstraction"]
    MATR["core::utils::matrices::build_matrices"]
    SIM["PyRunner (core::runner::Runner)"]
  end
  CLI --> PB --> LLM --> CLEAN --> SCORE
  SCORE --> RUN
  RUN --> SIM
  SIM --> WORLD
  RUN --> MATR
  HOMO --> MATR
  WORLD --> HOMO

Figure 1: Component diagram of the Python and Rust layers. Arrows indicate the main control and data flow between modules.

The Python layer also uses core_rust.generate_mdp for T and R and for the ideal abstraction, and it calls visualize_world_map and visualize_abstraction to generate artifacts under outputs/.