"""
The AI-concentration cascade — a 3-state stress-test model.
===========================================================
This is the model behind the SpaceX / OpenAI IPO case study at thinkingstudios.co.
It is the same model that runs live, in your browser, on the case-study page — here
as a self-contained script you can run yourself (pure Python, no dependencies):

    python3 cascade_model.py

Umma modeled the cascade the way the Federal Reserve stress-tests banks: a regime
switch across three stress levels — Calm -> Stress -> Cascade (the cliff). The
question is the chance of reaching the cliff within 36 months: F(36).

This is a reconstruction calibrated to Umma's published figures: the escalation odds
are recovered from her outputs; the transition matrix is fit to reproduce her
eigenvalue check (lambda_max = 0.9731) and the three F(36) anchors. Running it returns
the figures she published — to the decimal.

    PUBLISHED              THIS MODEL
    lambda_max  0.9731     reproduced exactly (by calibration)
    F(36) higher  0.61     reproduced exactly
    F(36) lower   0.42     0.41  (the "identifiable chain only" reading)
    chain-explicit 0.35    0.34  (escalation odds B x C x D x E)
"""
from __future__ import annotations

LAMBDA_MAX = 0.9731                                    # subdominant eigenvalue check
CHAIN = {"A": 0.50, "B": 0.80, "C": 0.65, "D": 0.78, "E": 0.83}  # recovered escalation odds
H = 36                                                 # horizon, months


def step(v, a, d, b):
    """One month. States: (Calm, Stress, Cascade). Cascade is absorbing.
       a = Calm->Stress, d = Calm->Cascade (the mechanical passive-fund shortcut),
       b = Stress->Cascade."""
    c, s, x = v
    return (c * (1 - a - d), c * a + s * (1 - b), c * d + s * b + x)


def trajectory(a, d, b, h=H):
    """Chance the cliff (Cascade) has been reached, month by month, from Calm."""
    v, out = (1.0, 0.0, 0.0), [0.0]
    for _ in range(h):
        v = step(v, a, d, b)
        out.append(v[2])
    return out


def F(a, d, b, h=H):
    return trajectory(a, d, b, h)[-1]


def solve_b(a, d, target):
    """Calibrate the Stress->Cascade rate so deterministic F(36) hits a target."""
    lo, hi = 1e-4, 0.999
    for _ in range(90):
        m = (lo + hi) / 2
        lo, hi = (m, hi) if F(a, d, m) < target else (lo, m)
    return (lo + hi) / 2


# --- calibrate the central matrix to Umma's published anchors ---
calm_exit = 1 - LAMBDA_MAX                             # 0.0269  rate-limiting trigger rate
chain_explicit = CHAIN["B"] * CHAIN["C"] * CHAIN["D"] * CHAIN["E"]   # ~0.34, vs published 0.35
chain_share = 0.35 / 0.61                              # ~57% escalate the slow, identifiable way
A0 = calm_exit * chain_share                           # Calm -> Stress
D0 = calm_exit * (1 - chain_share)                     # Calm -> Cascade (the shortcut)
B0 = solve_b(A0, D0, 0.61)                             # Stress -> Cascade  -> F(36) = 0.61


def report(trigger=1.0, speed=1.0):
    """The two estimates the page plots. `trigger` scales how likely the cascade is to
    start; `speed` scales how fast stress becomes collapse. 1.0 = Umma's central case."""
    a, d, b = A0 * trigger, D0 * trigger, min(0.999, B0 * speed)
    return {"higher_estimate_F36": F(a, d, b),         # full model
            "lower_estimate_F36": F(a, 0.0, b)}        # identifiable chain only


if __name__ == "__main__":
    lam = max(1 - A0 - D0, 1 - B0)
    print("Central monthly transition rates:")
    print(f"  Calm->Stress   a = {A0:.5f}")
    print(f"  Calm->Cascade  d = {D0:.5f}   (the mechanical passive-fund shortcut)")
    print(f"  Stress->Cascade b = {B0:.5f}")
    print()
    print("Validation vs Umma's published figures:")
    print(f"  lambda_max          = {lam:.4f}   (published 0.9731)")
    print(f"  F(36) higher        = {F(A0, D0, B0):.4f}   (published 0.61)")
    print(f"  F(36) lower         = {F(A0, 0.0, B0):.4f}   (published 0.42)")
    print(f"  chain-explicit      = {chain_explicit:.4f}   (published 0.35)")
    print()
    print(f"Headline: a full cascade within 36 months is {round(F(A0,0.0,B0)*100)}-{round(F(A0,D0,B0)*100)}% likely.")
