Backend Implementation Guide¶
This document provides guidance on implementing new backends for the computational framework.
Core Interface Requirements¶
Every backend must implement these core interfaces through its whisperer:
-
Terminal Condition Population:
-
Continuation Value Population:
-
Stage Solution:
-
Stage Simulation:
CompObject Interface¶
Every backend must package its computational functions in a CompObject that exposes:
- Value Function:
value_function(state)method - Decision Rule:
dcsn_rule(state)method
How these functions are implemented internally is entirely up to the backend.
Registration Process¶
To make a backend available to the framework:
from bellman.whisperers.registry import BackendRegistry
# Register your backend
BackendRegistry.register(
"my_backend",
MyBackendWhisperer,
"Description of my specialized backend"
)
After registration, users can select your backend like any other:
Configuration Management¶
Your backend should use the configuration management system:
from bellman.config import config
# Access backend-specific configuration
backend_config_path = config.backend_path("my_backend", "model_name", file_type="config")
Backend Implementation Strategies¶
1. Adapting Existing Computational Libraries¶
When wrapping an existing computational library:
class ExistingLibWhisperer(BaseWhisperer):
def __init__(self, **kwargs):
try:
import existing_lib
self.lib = existing_lib
except ImportError:
raise ImportError("existing_lib is required for this backend")
def solve_stage(self, stage):
# Translate stage to existing_lib format
lib_problem = self._translate_to_lib_format(stage)
# Solve using the library
lib_solution = self.lib.solve(lib_problem)
# Translate solution back to framework format
self._update_stage_with_solution(stage, lib_solution)
2. Building a New Computational Engine¶
When building a new computational engine:
class NewEngineWhisperer(BaseWhisperer):
def __init__(self, **kwargs):
from .my_engine import MyEngine
self.engine = MyEngine(**kwargs)
def solve_stage(self, stage):
# Use your custom engine
solution = self.engine.solve(stage.params, stage.methods)
# Update stage with solution
self._update_stage_with_solution(stage, solution)
3. Lazily Loading Dependencies¶
To avoid unnecessary dependencies:
class OptionalDependencyWhisperer(BaseWhisperer):
def __init__(self, **kwargs):
self.engine = None
def _ensure_engine(self):
if self.engine is None:
try:
from .expensive_import import ExpensiveEngine
self.engine = ExpensiveEngine()
except ImportError:
raise ImportError("ExpensiveEngine is required for this operation")
def solve_stage(self, stage):
self._ensure_engine()
# Now use the engine
self.engine.solve(stage)
Example Backends¶
See specific backend implementation guides: - Dolo Backend Implementation - HARK Backend Implementation