abdessamad-bourkibate's picture
Update engine/thresholds.py
a7636cc verified
from typing import Dict, Any, Tuple, List
import numpy as np
from .regimes import classify_regime, fragility_level
def compute_diagnostics(alpha: float, beta: float, D: float, k: float, tol: float, eps: float) -> Dict[str, Any]:
alpha = float(alpha); beta = float(beta)
D = float(D); k = float(k)
tol = float(tol); eps = float(eps)
lam = (alpha * D) - (beta * k) # λ = αD − βk
Delta = (beta * k) - (alpha * D) # Δ = βk − αD (stability margin)
denom = abs(alpha * D) + abs(beta * k) + eps
F = abs(Delta) / denom # normalized fragility/proximity
regime = classify_regime(lam, tol)
frag = fragility_level(F)
# Boundary expression: stable if k > (α/β)D (when β>0)
boundary_k = (alpha / beta) * D if beta != 0 else float("nan")
margin_to_boundary = k - boundary_k # >0 means above boundary
# Local sensitivities of λ
ranked = sorted(
{
"∂λ/∂α = D": float(D),
"∂λ/∂D = α": float(alpha),
"∂λ/∂β = −k": float(-k),
"∂λ/∂k = −β": float(-beta),
}.items(),
key=lambda kv: abs(kv[1]),
reverse=True
)
return {
"alpha": alpha, "beta": beta, "D": D, "k": k,
"lambda": float(lam),
"Delta": float(Delta),
"F": float(F),
"regime": regime,
"fragility": frag,
"boundary_k": float(boundary_k),
"margin_to_boundary": float(margin_to_boundary),
"sens_ranked": ranked,
}
def interpret_governance(regime: str, fragility: str, Delta: float, margin_to_boundary: float) -> Dict[str, str]:
"""
Decision-facing interpretation (structural, not behavioral).
"""
if regime == "Unstable":
posture = "Mandatory"
decision = "Immediate stabilization required: raise k and/or reduce D to restore Δ > 0."
risk = "Escalation expected if unchanged; structural governance failure probability rises."
return {"posture": posture, "decision": decision, "risk": risk}
if regime == "Near-boundary":
posture = "Preventive"
decision = "Treat as fragile: widen margin (increase k or reduce D) + define explicit intervention triggers."
risk = "Small drift can flip stability; high sensitivity zone."
return {"posture": posture, "decision": decision, "risk": risk}
# Stable
if fragility == "High":
posture = "Adaptive"
decision = "Stable but fragile: increase Δ minimally (proportional adjustments) to improve robustness."
risk = "Stability exists, but it can be lost under minor parameter perturbations."
return {"posture": posture, "decision": decision, "risk": risk}
if fragility == "Moderate":
posture = "Adaptive"
decision = "Maintain stability and monitor drift; keep margin safely positive without unnecessary intensity."
risk = "Moderate robustness; avoid overreach if smaller k preserves stability."
return {"posture": posture, "decision": decision, "risk": risk}
# Low fragility
posture = "Advisory"
decision = "Robust stability: guidance + periodic review. Consider proportionality if k greatly exceeds boundary."
risk = "Low escalation probability under small perturbations."
return {"posture": posture, "decision": decision, "risk": risk}
def euler_simulation(alpha: float, beta: float, D: float, k: float, R0: float, T: float, n: int) -> Tuple[np.ndarray, np.ndarray]:
alpha = float(alpha); beta = float(beta)
D = float(D); k = float(k)
R0 = float(R0); T = float(T)
n = int(n)
lam = (alpha * D) - (beta * k)
t = np.linspace(0.0, T, n)
dt = float(t[1] - t[0])
R = np.zeros_like(t)
R[0] = max(R0, 1e-12)
for i in range(1, len(t)):
R[i] = R[i-1] + dt * (lam * R[i-1])
R[i] = max(R[i], 0.0)
return t, R