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