Orchestrator: src/12_execute.py (108 lines)
Implementation Layer: src/execute/
This module is responsible for running GNN models that have been rendered into framework-specific simulation code by Step 11 (11_render.py).
| Framework | Language | Subfolder | Script Pattern | Status |
|---|---|---|---|---|
| PyMDP | Python | pymdp/ |
*_pymdp.py |
✅ Full support |
| RxInfer.jl | Julia | rxinfer/ |
*_rxinfer.jl |
✅ Full support |
| ActiveInference.jl | Julia | activeinference_jl/ |
*_activeinference.jl |
✅ Full support |
| JAX | Python | jax/ |
*_jax.py |
✅ Full support |
| DisCoPy | Python | discopy/ |
*_discopy.py |
✅ Full support |
| PyTorch | Python | pytorch/ |
*_pytorch.py |
✅ Full support |
| NumPyro | Python | numpyro/ |
*_numpyro.py |
✅ Full support |
JAX, NumPyro, PyTorch, and DisCoPy are core dependencies (uv sync). If the environment is incomplete, their scripts are skipped (not failed). Julia frameworks require Julia installed.
Purpose: Execute rendered simulation scripts across multiple frameworks (PyMDP, RxInfer.jl, ActiveInference.jl, JAX, DisCoPy, PyTorch, NumPyro).
Pipeline Step: Step 12: Execution (12_execute.py)
Category: Simulation / Execution
Status: ✅ Production Ready
Version: 1.6.0
Last Updated: 2026-01-21
- Execute Python simulation scripts (PyMDP, JAX, DisCoPy)
- Execute Julia simulation scripts (RxInfer.jl, ActiveInference.jl)
- Capture simulation results and logs
- Handle execution errors gracefully
- Generate execution reports
- Multi-framework execution support
- Skip vs fail: JAX, NumPyro, PyTorch, and DisCoPy are core dependencies; if the environment is incomplete, scripts are skipped (not run) and reported as "skipped" — they do not count as execution failures. Repair with
uv sync. Julia backends still require a local Julia install. - Graceful degradation when frameworks unavailable
- Automatic PyMDP package detection (distinguishes correct vs wrong package variants)
- Path collection with deduplication (prevents nested directory issues)
- Comprehensive error logging
- Result capture and validation
- Execution timeout handling
- Distributed execution across a Ray or Dask cluster for parallel script/parameter-sweep dispatch (
src/execute/distributed.py,--distributed,--execution-workers,--backend {ray,dask})
process_execute(target_dir: Path, output_dir: Path, verbose: bool = False, logger: Optional[logging.Logger] = None, **kwargs) -> bool
Description: Main execution function called by orchestrator (12_execute.py). Executes rendered simulation scripts across multiple frameworks.
Parameters:
target_dir(Path): Directory containing rendered scripts (typically output from Step 11)output_dir(Path): Output directory for execution resultsverbose(bool): Enable verbose logging (default: False)logger(Optional[logging.Logger]): Logger instance (default: None)frameworks(str): Frameworks to execute ("all", "lite", or comma-separated list, default: "all")"all": Execute all available frameworks"lite": Execute only PyMDP, JAX, DisCoPy (no Julia)- Comma-separated:
"pymdp,jax"for specific frameworks
simulation_engine(str): Engine to use ("auto", "pymdp", "rxinfer", etc., default: "auto")validate_only(bool): Only validate scripts, don't execute (default: False)timeout(int): Execution timeout per script in seconds (default: 3600, CLI:--timeout)distributed(bool): Run scripts and parameter sweeps in parallel across a Ray/Dask cluster (default: False, CLI:--distributed)execution_workers(int): Number of local or distributed workers for rendered script execution (default: 1, CLI:--execution-workers)backend(str): Backend for distributed execution,"ray"or"dask"(default:"ray", CLI:--backend {ray,dask})parallel(bool): Execute scripts in parallel (default: False)**kwargs: Additional framework-specific options
Returns: bool - True if execution succeeded, False otherwise
Example:
from execute import process_execute
from pathlib import Path
import logging
logger = logging.getLogger(__name__)
success = process_execute(
target_dir=Path("output/11_render_output"),
output_dir=Path("output/12_execute_output"),
verbose=True,
frameworks="pymdp,jax",
timeout=600
)execute_simulation_from_gnn(gnn_file: Path, framework: str, output_dir: Path, **kwargs) -> Dict[str, Any]
Description: Execute simulation for specific GNN file and framework.
Parameters:
gnn_file(Path): Path to GNN fileframework(str): Framework to use ("pymdp", "rxinfer", "activeinference_jl", "jax", "discopy")output_dir(Path): Output directory for execution results**kwargs: Framework-specific execution options
Returns: Dict[str, Any] - Execution results dictionary with:
success(bool): Whether execution succeededreturn_code(int): Process return codestdout(str): Standard outputstderr(str): Standard errorduration(float): Execution duration in secondsoutput_files(List[Path]): Generated output files
Description: Get health status of execution environment and framework availability.
Returns: Dict[str, Any] - Health status dictionary with:
pymdp_available(bool): PyMDP availabilityrxinfer_available(bool): RxInfer.jl availabilityactiveinference_jl_available(bool): ActiveInference.jl availabilityjax_available(bool): JAX availabilitydiscopy_available(bool): DisCoPy availabilityjulia_available(bool): Julia installation statuspython_version(str): Python versionjulia_version(Optional[str]): Julia version if available
Module: execute.pymdp.package_detector
Functions:
detect_pymdp_installation() -> Dict[str, Any]: Detect which PyMDP package variant is installed- Returns detection results including
correct_package,wrong_package,has_agent,has_mdp_solver
- Returns detection results including
is_correct_pymdp_package() -> bool: Check if correct package (inferactively-pymdp) is installedget_pymdp_installation_instructions() -> str: Get actionable installation instructionsvalidate_pymdp_for_execution() -> Dict[str, Any]: Validate PyMDP is ready for execution- Returns
readystatus, detection results, and installation instructions
- Returns
Usage:
from execute.pymdp.package_detector import detect_pymdp_installation, is_correct_pymdp_package
detection = detect_pymdp_installation()
if detection.get("wrong_package"):
print("Wrong PyMDP package installed - install inferactively-pymdp")
elif not detection.get("correct_package"):
print("PyMDP not installed - install inferactively-pymdp")simulation_engine(str): Engine to use for execution (default:"auto")"auto": Automatically select best available engine"pymdp": Use PyMDP for Python simulations"rxinfer": Use RxInfer.jl for Julia simulations"activeinference_jl": Use ActiveInference.jl"jax": Use JAX framework"discopy": Use DisCoPy for categorical diagrams
timeout(int): Execution timeout in seconds (default:3600)validate_only(bool): Only validate scripts, don't execute (default:False)capture_output(bool): Capture stdout/stderr (default:True)parallel_execution(bool): Execute scripts in parallel (default:False)
distributed(bool, CLI:--distributed): Run scripts and model parameter sweeps in parallel across a Ray/Dask cluster (default:False)execution_workers(int, CLI:--execution-workers): Number of local or distributed workers for rendered script execution (default:1)backend(str, CLI:--backend {ray,dask}): Backend to use for distributed execution (default:"ray"); implemented bysrc/execute/distributed.py'sDispatcherclass
julia_path(str): Path to Julia executable (default: auto-detect)python_env(str): Python environment to use (default: current environment)jax_device(str): JAX device to use (default:"cpu", options:"cpu","gpu")
subprocess- Script executionjson- Result serialization
inferactively-pymdp- PyMDP simulation engine (package name:inferactively-pymdp, recovery: skip PyMDP)- Note: The correct package name is
inferactively-pymdp, notpymdp - The execute module automatically detects wrong package variants
- Note: The correct package name is
julia- Julia runtime (recovery: skip Julia scripts)jax- JAX framework (recovery: skip JAX)
from execute import process_execute
success = process_execute(
target_dir=Path("input/gnn_files"),
output_dir=Path("output/12_execute_output"),
simulation_engine="auto"
)# Fan out rendered scripts / parameter sweeps across a local or remote Ray cluster
python src/12_execute.py --target-dir output/11_render_output --output-dir output \
--distributed --execution-workers 4 --backend ray
# Use Dask instead of Ray
python src/12_execute.py --target-dir output/11_render_output --output-dir output \
--distributed --execution-workers 4 --backend daskexecution_results.json- Execution results summaryexecution_report.md- Human-readable reportexecution_logs/*.log- Per-script execution logssimulation_data/*.json- Simulation output data
output/12_execute_output/
├── execution_results/
│ ├── execution_results.json
│ ├── execution_report.md
│ └── execution_logs/
│ ├── pymdp_simulation.log
│ ├── rxinfer_simulation.log
│ └── activeinference_simulation.log
└── simulation_data/
└── results_*.json
- Duration: 32.5s
- Memory: Peak 19.26 MB, Final 13.96 MB
- Status: SUCCESS_WITH_WARNINGS
- Scripts Found: 5
- Scripts Failed: 5 (dependency issues)
- PyMDP: ~1-5 seconds
- RxInfer.jl: ~10-20 seconds (JIT compilation)
- ActiveInference.jl: ~10-15 seconds
- JAX: ~2-8 seconds (with GPU)
- DisCoPy: ~1-3 seconds
- PyMDP unavailable: Log warning, skip PyMDP scripts
- Julia unavailable: Log warning, skip Julia scripts
- JAX unavailable: Log warning, skip JAX scripts
- Script errors: Capture stderr, continue with other scripts
- Timeout: 3600s per script (configurable via
--timeout)
- Dependency Errors: Framework not installed
- Syntax Errors: Generated code has errors
- Runtime Errors: Simulation crashes
- Timeout Errors: Execution exceeds limit
- Input: Receives rendered simulation scripts from Step 11 (render)
- Output: Generates execution results for Step 13 (llm analysis), Step 16 (analysis), and Step 23 (report generation)
- Dependencies: Requires rendered code from
11_render.pyoutput
- render/: Consumes rendered simulation scripts
- llm/: Provides execution results for LLM analysis
- analysis/: Provides execution data for statistical analysis
- report/: Provides execution summaries for reports
- PyMDP: Executes Python Active Inference simulations
- Julia Runtime: Executes Julia simulation scripts (RxInfer.jl, ActiveInference.jl)
- JAX: Executes JAX-based simulations
- DisCoPy: Executes categorical diagram computations
11_render.py (Code generation)
↓
12_execute.py (Script execution)
↓
├→ 13_llm.py (LLM analysis of results)
├→ 16_analysis.py (Statistical analysis)
├→ 23_report.py (Execution reports)
└→ output/12_execute_output/ (Execution results)
src/tests/execute/test_execute_overall.pysrc/tests/execute/test_execute_pymdp_integration.pysrc/tests/execute/test_execute_pymdp_package.py
- Current: 79%
- Target: 85%+
- Multi-framework execution
- Error handling and recovery
- Result capture and validation
- Timeout handling
execute.run_simulation- Execute simulation scriptexecute.validate_environment- Validate execution environmentexecute.get_health_status- Get framework health statusexecute.analyze_error- Analyze execution errors
@mcp_tool("execute.run_simulation")
def run_simulation_tool(script_path: str, framework: str) -> Dict[str, Any]:
"""Execute simulation script"""
# Implementationsrc/execute/mcp.py- MCP tool registrations
Symptom: Julia scripts fail to execute
Cause: Julia not installed or not in PATH
Solution:
- Install Julia:
brew install julia(macOS) or download from julialang.org - Verify Julia installation:
julia --version - Check Julia is in PATH:
which julia - Install required Julia packages if needed
Symptom: Execution fails with import errors
Cause: Required packages not installed in environment
Solution:
- Install framework dependencies:
uv pip install inferactively-pymdp jax - Note: The correct PyMDP package name is
inferactively-pymdp, notpymdp - For Julia: Install packages via
julia -e 'using Pkg; Pkg.add("RxInfer")' - Check framework-specific requirements in documentation
Symptom: Error message "Wrong pymdp package installed. Found 'pymdp' with MDP/MDPSolver"
Cause: The wrong pymdp package (with MDP/MDPSolver) is installed instead of inferactively-pymdp
Solution:
- Uninstall wrong package:
uv pip uninstall pymdp - Install correct package:
uv pip install inferactively-pymdp - Or use setup module:
python src/1_setup.py --install_optional --optional_groups pymdp - The execute module automatically detects wrong package variants and provides clear error messages
Symptom: Scripts timeout before completion
Cause: Simulation too complex or timeout too short
Solution:
- Increase timeout beyond the default 3600s (1 hour):
--timeout 7200(2 hours) - Simplify model complexity
- Use faster frameworks (JAX) for large models
- Process models individually instead of batch
Features:
- Multi-framework execution support
- Graceful degradation when frameworks unavailable
- Comprehensive error logging
- Result capture and validation
- Execution timeout handling
- Distributed execution across a Ray/Dask cluster (
--distributed,--execution-workers,--backend)
Known Issues:
- None currently
- Future: Real-time execution monitoring
Last Updated: 2026-01-21 Maintainer: GNN Pipeline Team Status: ✅ Production Ready Version: 1.6.0 Architecture Compliance: ✅ 100% Thin Orchestrator Pattern
- README: Module Overview
- AGENTS: Agentic Workflows
- SPEC: Architectural Specification
- SKILL: Capability API
Source Reference: src/execute