Policy Engine¶
Purpose: The PolicyEngine is the adaptive “brain” of the simulation. It centralizes the logic for enforcing operational rules and adaptive behaviors. It continuously monitors the simulation’s performance via the EvaluationEngine and applies corrective actions—or “policies”—to steer the system towards its defined goals.
Architecture¶
The engine is designed to be modular and extensible, revolving around three key concepts:
PolicyEngine: The central manager class. Its primary responsibilities are:Maintaining a registry of all available policies.
Iterating through all enabled policies during each simulation step.
Calling the
applymethod on each policy, providing it with the latest simulation performance data.Collecting the results (or “effects”) of each policy application for logging and analysis.
PolicyProtocol: This is the core contract defined inpolicy_protocol.py. For an object to be considered a policy, it must conform to this protocol, which requires it to have:id: A unique string identifier (e.g.,PLCY-ENV-DUST-THROTTLE).name: A human-readable name.enabled: A boolean flag to easily turn the policy on or off.apply(engine, evaluation_result): The main method containing the policy’s logic.
EvaluationResult: This is the sole input for the policy engine’s decision-making process. It is a comprehensive data object provided by theEvaluationEnginethat contains the final scores and metric values for the current simulation step. ThePolicyEnginedoes not perform calculations; it reacts to the data in this object.
Operational Flow¶
The policy application process is a clear, sequential part of the main simulation loop.
Input: After the
WorldSystemhas stepped all sectors and theEvaluationEnginehas calculated all scores, theWorldSystemcallspolicy_engine.apply_policies(), passing the finalEvaluationResult.Iteration: The
PolicyEngineloops through its internal list of registered policies.Execution: For each policy where
enabledisTrue, it calls that policy’sapply()method.Logic: Inside the
apply()method, the policy inspects theevaluation_resultto check the status of relevant metrics. For example, theDustCoverageThrottlePolicychecks the score for theIND-DUST-COVmetric.Action: If a condition is met, the policy takes action by calling a method on one of the sectors. It can access any sector via the
engine.worldobject passed into theapplymethod (e.g.,engine.world.sectors['science'].set_throttle_factor(0.5)).Output: The
apply()method returns a dictionary summarizing the actions it took (its “effects”). ThePolicyEnginecollects these effects from all active policies and returns them to theWorldSystemfor logging.
How to Create a New Policy¶
Adding a new policy is a straightforward process designed to be self-contained.
Step 1: Define the Policy Class¶
Create a new class that implements the Policy protocol. For this example, we’ll create a policy that throttles science activity if there is a power shortage.
# In a file like /proxima_model/policy_engine/economic_policies.py
from __future__ import annotations
from typing import Dict, Any, TYPE_CHECKING
import logging
# ... (TYPE_CHECKING imports) ...
logger = logging.getLogger(__name__)
class PowerShortageContingencyPolicy:
"""
Reduces science activity if there is a power shortage to preserve
power for essential systems.
"""
id = "PLCY-ECON-POWER-CONTINGENCY"
name = "Power Shortage Contingency"
enabled = True
def apply(self, engine: "PolicyEngine", evaluation_result: "EvaluationResult") -> Dict[str, Any]:
"""Apply the power shortage policy."""
# 1. Find the relevant metric score
power_metrics = evaluation_result.performance_metrics
power_shortage = power_metrics.get("PWR-SHORTAGE-KW", 0.0)
effects = {"power_shortage_detected_kw": power_shortage, "throttle_applied": "none"}
# 2. Apply logic
if power_shortage > 0:
# 3. Take action by calling a method on a sector
throttle_factor = 0.8 # Drastically reduce science activity
engine.world.sectors['science'].set_throttle_factor(throttle_factor)
effects["throttle_applied"] = "science"
effects["new_throttle_factor"] = throttle_factor
logger.warning(f"⚠️ {self.name}: Power shortage of {power_shortage:.2f} kW detected. Throttling science sector.")
else:
# Ensure throttle is reset if conditions are normal
engine.world.sectors['science'].set_throttle_factor(0.0)
return effects
Step 2: Register the New Policy¶
In policy_engine.py, import your new policy class and add an instance of it to the _policies list in the __init__ method.
# /proxima_model/policy_engine/policy_engine.py
# ... (existing imports) ...
from proxima_model.policy_engine.environmental_policies import DustCoverageThrottlePolicy
from proxima_model.policy_engine.science_policies import ScienceProductionRate
from proxima_model.policy_engine.economic_policies import PowerShortageContingencyPolicy # <-- IMPORT
class PolicyEngine:
# ...
def __init__(self, world):
self.world = world
self._policies: List[Policy] = [
DustCoverageThrottlePolicy(),
ScienceProductionRate(),
PowerShortageContingencyPolicy() # <-- REGISTER
]
# ... (rest of the class) ...
With these two changes, the new policy is fully integrated and will be executed on every simulation step.