| | 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) |
| | Delta = (beta * k) - (alpha * D) |
| | denom = abs(alpha * D) + abs(beta * k) + eps |
| | F = abs(Delta) / denom |
| |
|
| | regime = classify_regime(lam, tol) |
| | frag = fragility_level(F) |
| |
|
| | |
| | boundary_k = (alpha / beta) * D if beta != 0 else float("nan") |
| | margin_to_boundary = k - boundary_k |
| |
|
| | |
| | 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} |
| |
|
| | |
| | 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} |
| |
|
| | |
| | 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 |