import math
import os
import numpy as np
try:
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
HAS_MPL = True
except ImportError:
HAS_MPL = False
print("matplotlib not found -- tables only.")
H_SIM = 150 L_SIM = 165 CW_SIM = 500 K_SIM = 1 MU = 1.0
H_BENCH = 114_688
L_BENCH = 131_072
CW_BENCH = 32_768
K_BENCH = 32
N_VALUES = [2, 4, 8, 16]
RHO_DENSE = np.linspace(0.01, 0.99, 300)
def mmh_pmf(rho: float, H: int) -> np.ndarray:
if abs(rho - 1.0) < 1e-9:
return np.ones(H + 1) / (H + 1)
q = np.arange(H + 1, dtype=np.float64)
unnorm = rho ** q
return unnorm / unnorm.sum()
def mmh_moments(rho: float, H: int):
pmf = mmh_pmf(rho, H)
q = np.arange(H + 1, dtype=np.float64)
mu = float(np.dot(pmf, q))
var = float(np.dot(pmf, q ** 2)) - mu ** 2
return mu, var
def deflection_prob(rho: float, H: int) -> float:
pmf = mmh_pmf(rho, H)
return float(pmf[H])
def solve_sc(rho0: float, H: int, mu: float = 1.0,
tol: float = 1e-8, max_iter: int = 500) -> float:
r = rho0
for _ in range(max_iter):
pd = deflection_prob(r, H)
r_new = min(rho0 * (1.0 + pd), 0.9999)
if abs(r_new - r) < tol:
return r_new
r = r_new
return r
def l1_mean_queue(rho0: float, H: int) -> float:
rhostar = solve_sc(rho0, H)
mu_q, _ = mmh_moments(rhostar, H)
return mu_q
def l1_drift_bound(rho0: float, H: int) -> float:
rhostar = solve_sc(rho0, H)
if rhostar >= 1.0:
return float('inf')
return (1.0 + rhostar) / (2.0 * (1.0 - rhostar))
def l2_spectral_gap_numerical(rho0: float, H: int) -> float:
rhostar = solve_sc(rho0, H)
lam = MU * rhostar
n = H + 1
diag_S = np.zeros(n)
for q in range(n):
up_rate = lam if q < H else 0.0
down_rate = MU if q > 0 else 0.0
diag_S[q] = -(up_rate + down_rate)
off = math.sqrt(lam * MU) if lam > 0 else 0.0
off_diag = np.full(n - 1, off)
S = np.diag(diag_S) + np.diag(off_diag, 1) + np.diag(off_diag, -1)
eigvals = np.linalg.eigvalsh(S) eigvals_sorted = np.sort(np.abs(eigvals))
return float(eigvals_sorted[1]) if len(eigvals_sorted) > 1 else 0.0
def l2_spectral_gap_exact(rho0: float, H: int) -> float:
return l2_spectral_gap_numerical(rho0, H)
def l2_spectral_gap_approx(rho0: float, H: int = None) -> float:
H_use = H if H is not None else H_SIM
rhostar = solve_sc(rho0, H_use)
if rhostar >= 1.0:
return 0.0
return MU * (1.0 - math.sqrt(rhostar)) ** 2
def l2_mixing_time(rho0: float, H: int, eps: float = 0.01) -> float:
gamma = l2_spectral_gap_numerical(rho0, H)
if gamma < 1e-15:
return float('inf')
return math.log(1.0 / eps) / gamma
def l3_burst_capacity(rho0: float, H: int, L: int, N: int,
CW: int, K: int) -> float:
rhostar = solve_sc(rho0, H)
mu_q, _ = mmh_moments(rhostar, H)
slack_per_worker = max(L - mu_q, 0.0)
return N * slack_per_worker + CW * K
def l3_burst_capacity_worst(rho0: float, H: int, L: int, N: int,
CW: int, K: int) -> float:
slack_per_worker = max(L - H, 0.0)
return N * slack_per_worker + CW * K
def l4_warehouse_rates(rho0: float, H: int, N: int):
rhostar = solve_sc(rho0, H)
pd = deflection_prob(rhostar, H)
lam0 = rho0 * MU
Lambda_W = N * lam0 * (pd ** (N // 2))
Lambda_D = N * MU * (1.0 - pd)
return Lambda_W, Lambda_D
def l4_crash_time(rho0: float, H: int, N: int, CW: int) -> float:
Lambda_W, Lambda_D = l4_warehouse_rates(rho0, H, N)
Delta = Lambda_W - Lambda_D
if Delta <= 0:
return float('inf')
return CW / Delta
def l4_wh_stable_threshold(H: int, N: int) -> float:
for rho0_test in np.linspace(0.99, 0.01, 5000):
rhostar = solve_sc(rho0_test, H)
pd = deflection_prob(rhostar, H)
if pd < 1e-15:
continue
lhs = rho0_test * (pd ** (N // 2))
rhs = 1.0 - pd
if lhs >= rhs:
return rho0_test
return 1.0
def print_all_tables():
print("\n" + "=" * 70)
print("DTA-V3 Stability Analysis -- All Four Levels")
print(f"H={H_SIM}, L={L_SIM}, CW={CW_SIM}, K={K_SIM}, mu={MU}")
print("=" * 70)
print("\n--- L1: Throughput Stability (Foster-Lyapunov) ---")
print(f" {'rho0':>6} {'rho*':>6} {'q_bar':>8} {'F-L bound':>10} "
f"{'stable?':>8}")
for rho0 in [0.2, 0.4, 0.6, 0.7, 0.8, 0.9, 0.95, 1.0, 1.05]:
rs = min(solve_sc(rho0, H_SIM), 1.0)
mu_q = l1_mean_queue(rho0, H_SIM)
bound = l1_drift_bound(rho0, H_SIM)
stab = "YES" if rho0 < 1.0 else "NO"
print(f" {rho0:>6.2f} {rs:>6.4f} {mu_q:>8.2f} "
f"{bound:>10.2f} {stab:>8}")
H_L2 = 40
print(f"\n--- L2: Spectral Gap and Mixing Time (H={H_L2} for speed) ---")
print(f" {'rho0':>6} {'gamma_num':>12} {'gamma_approx':>13} "
f"{'t_mix(1%)':>12} {'t_mix(0.1%)':>13}")
for rho0 in [0.3, 0.5, 0.7, 0.8, 0.9, 0.95, 0.99]:
gn = l2_spectral_gap_numerical(rho0, H_L2)
ga = l2_spectral_gap_approx(rho0, H_L2)
tm1 = l2_mixing_time(rho0, H_L2, eps=0.01)
tm2 = l2_mixing_time(rho0, H_L2, eps=0.001)
print(f" {rho0:>6.2f} {gn:>12.5f} {ga:>13.5f} "
f"{tm1:>12.2f} {tm2:>13.2f}")
print("\n--- L3: Burst Absorption Capacity (simulation scale) ---")
print(f" {'rho0':>6} {'q_bar':>8} "
+ " ".join(f"B*(N={N})" for N in N_VALUES))
for rho0 in [0.3, 0.5, 0.7, 0.8, 0.9, 0.95]:
rs = solve_sc(rho0, H_SIM)
mu_q, _ = mmh_moments(rs, H_SIM)
caps = [l3_burst_capacity(rho0, H_SIM, L_SIM, N, CW_SIM, K_SIM)
for N in N_VALUES]
row = f" {rho0:>6.2f} {mu_q:>8.2f} "
row += " ".join(f"{c:>10.0f}" for c in caps)
print(row)
H_L4 = 5
N_L4 = 2
print(f"\n--- L4: Crash Time vs Overload (N={N_L4}, H={H_L4} for visibility) ---")
print(f" {'rho0':>6} {'p_d':>8} {'Lambda_W':>10} {'Lambda_D':>10} "
f"{'Delta':>10} {'T_crash':>12} {'stable?':>8}")
for rho0 in [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0]:
rs = solve_sc(rho0, H_L4)
pd = deflection_prob(rs, H_L4)
LW, LD = l4_warehouse_rates(rho0, H_L4, N_L4)
Delta = LW - LD
Tc = l4_crash_time(rho0, H_L4, N_L4, CW_SIM)
stab = "YES" if Tc == float('inf') else "NO"
Tc_str = "inf" if Tc == float('inf') else f"{Tc:.2f}"
print(f" {rho0:>6.2f} {pd:>8.5f} {LW:>10.5f} {LD:>10.5f} "
f"{Delta:>10.5f} {Tc_str:>12} {stab:>8}")
print("\n--- L3: Burst Capacity at BENCHMARK scale ---")
print(f" H={H_BENCH}, L={L_BENCH}, CW={CW_BENCH}, K={K_BENCH}")
print(f" {'rho0':>6} " + " ".join(f"B*(N={N})" for N in [2, 4, 8]))
for rho0 in [0.3, 0.5, 0.7, 0.9]:
caps = [l3_burst_capacity(rho0, H_BENCH, L_BENCH, N,
CW_BENCH, K_BENCH)
for N in [2, 4, 8]]
row = f" {rho0:>6.2f} " + " ".join(f"{c:>14,.0f}" for c in caps)
print(row)
def make_plots(outdir: str):
if not HAS_MPL:
return
colors = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd"]
fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))
ax = axes[0]
rho0_stable = RHO_DENSE[RHO_DENSE < 0.999]
mean_q = [l1_mean_queue(r, H_SIM) for r in rho0_stable]
fl_bnd = [l1_drift_bound(r, H_SIM) for r in rho0_stable]
ax.plot(rho0_stable, mean_q, "b-", lw=2.0, label=r"$\bar{q}(\varrho_0)$ (mean field)")
ax.plot(rho0_stable, fl_bnd, "r--", lw=1.5,
label=r"F-L bound: $(1+\varrho^*)/(2(1-\varrho^*))$")
ax.axhline(H_SIM, color="gray", ls=":", lw=1.2,
label=f"Watermark $H={H_SIM}$")
ax.axvline(1.0, color="black", ls="-.", lw=1.0, alpha=0.5, label=r"$\varrho_0=1$ (capacity)")
ax.set_xlabel(r"Offered load $\varrho_0 = \lambda_0\delta$", fontsize=11)
ax.set_ylabel("Mean queue length", fontsize=11)
ax.set_title("L1: Throughput stability\n"
r"$\bar{q}$ is finite iff $\varrho_0 < 1$", fontsize=10)
ax.legend(fontsize=9)
ax.set_xlim(0, 1.02)
ax.set_ylim(0, H_SIM * 1.05)
ax.grid(True, alpha=0.3, ls="--")
ax = axes[1]
rhostar_vals = [solve_sc(r, H_SIM) for r in rho0_stable]
ax.plot(rho0_stable, rhostar_vals, "b-", lw=2.0, label=r"$\varrho^*$ (self-consistent)")
ax.plot(rho0_stable, rho0_stable, "k--", lw=1.2, alpha=0.5,
label=r"$\varrho^* = \varrho_0$ (no deflection)")
ax.set_xlabel(r"Offered load $\varrho_0$", fontsize=11)
ax.set_ylabel(r"Effective load $\varrho^*$", fontsize=11)
ax.set_title(r"Self-consistency: deflection raises $\varrho^* > \varrho_0$", fontsize=10)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3, ls="--")
fig.tight_layout()
p = os.path.join(outdir, "stability_L1_mean_queue.png")
fig.savefig(p, dpi=150); plt.close(fig); print(f" [saved] {p}")
H_L2_plot = 40 fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))
ax = axes[0]
rho_l2 = RHO_DENSE[RHO_DENSE < 0.98]
gamma_num = np.array([l2_spectral_gap_numerical(r, H_L2_plot) for r in rho_l2])
gamma_approx = np.array([l2_spectral_gap_approx(r, H_L2_plot) for r in rho_l2])
pos = (gamma_num > 1e-10) & (gamma_approx > 1e-10)
ax.plot(rho_l2[pos], gamma_num[pos], "b-", lw=2.0,
label=f"Numerical eigenvalue ($H={H_L2_plot}$)")
ax.plot(rho_l2[pos], gamma_approx[pos], "r--", lw=1.5,
label=r"Approx $\mu(1-\sqrt{\varrho^*})^2$ ($H\to\infty$)")
ax.set_xlabel(r"$\varrho_0$", fontsize=11)
ax.set_ylabel(r"Spectral gap $\gamma$", fontsize=11)
ax.set_title("L2: Spectral gap vs load\n"
r"$\gamma \to 0$ as $\varrho_0 \to 1$ (critical slowing-down)", fontsize=10)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3, ls="--")
ax.set_yscale("log")
ax = axes[1]
tmix_arr = np.array([l2_mixing_time(r, H_L2_plot, eps=0.01) for r in rho_l2])
mask = np.isfinite(tmix_arr) & (tmix_arr > 0) & (tmix_arr < 1e6)
ax.plot(rho_l2[mask], tmix_arr[mask], "b-", lw=2.0, label=r"$t_{\rm mix}(1\%)$")
mid = len(rho_l2[mask]) // 2
if mid > 0 and tmix_arr[mask][mid] > 0:
ref = 1.0 / (1.0 - rho_l2[mask]) ** 2
scale = tmix_arr[mask][mid] / ref[mid]
ax.plot(rho_l2[mask], ref * scale,
"k--", lw=1.2, alpha=0.7, label=r"$\propto (1-\varrho_0)^{-2}$ reference")
ax.set_xlabel(r"$\varrho_0$", fontsize=11)
ax.set_ylabel("Mixing time (service units)", fontsize=11)
ax.set_title("L2: Critical slowing-down\n"
r"$t_{\rm mix} \sim (1-\varrho_0)^{-2}$ near capacity", fontsize=10)
ax.set_yscale("log")
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3, ls="--")
fig.tight_layout()
p = os.path.join(outdir, "stability_L2_spectral_gap.png")
fig.savefig(p, dpi=150); plt.close(fig); print(f" [saved] {p}")
fig, ax = plt.subplots(figsize=(8, 4.5))
for idx, N in enumerate(N_VALUES):
caps = [l3_burst_capacity(r, H_SIM, L_SIM, N, CW_SIM, K_SIM)
for r in RHO_DENSE]
ax.plot(RHO_DENSE, caps, color=colors[idx], lw=1.8, label=f"N={N}")
wh_floor = CW_SIM * K_SIM
ax.axhline(wh_floor, color="gray", ls=":", lw=1.2,
label=f"Warehouse floor $C_WK={wh_floor}$")
ax.set_xlabel(r"$\varrho_0$", fontsize=11)
ax.set_ylabel(r"Expected burst capacity $\mathbb{E}[B^*]$ (tasks)", fontsize=11)
ax.set_title("L3: Adversarial burst absorption capacity\n"
r"$B^* = N(L-\bar{q}) + C_W K$, decreasing in $\varrho_0$", fontsize=10)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3, ls="--")
fig.tight_layout()
p = os.path.join(outdir, "stability_L3_burst_capacity.png")
fig.savefig(p, dpi=150); plt.close(fig); print(f" [saved] {p}")
H_L4 = 5
N_L4 = 2
fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))
ax = axes[0]
rho_over = np.linspace(1.0, 15.0, 400)
Tc_vals = [l4_crash_time(r, H_L4, N_L4, CW_SIM) for r in rho_over]
Tc_arr = np.array(Tc_vals, dtype=float)
finite = np.isfinite(Tc_arr) & (Tc_arr > 0) & (Tc_arr < 1e8)
if finite.any():
ax.plot(rho_over[finite], Tc_arr[finite], "b-", lw=2.0,
label=f"N={N_L4}, H={H_L4} (numerical)")
Delta_arr = np.array([l4_warehouse_rates(r, H_L4, N_L4)[0]
- l4_warehouse_rates(r, H_L4, N_L4)[1]
for r in rho_over[finite]])
pos_delta = Delta_arr > 1e-12
if pos_delta.any():
ref_tc = CW_SIM / Delta_arr[pos_delta]
ax.plot(rho_over[finite][pos_delta], ref_tc, "r--", lw=1.5,
label=r"$C_W/\Delta$ (Theorem 4.3)")
ax.set_yscale("log")
crossover = rho_over[finite][0] if finite.any() else None
if crossover is not None:
ax.axvline(crossover, color="gray", ls="-.", lw=1.0,
label=f"Overload threshold ~{crossover:.1f}")
ax.set_xlabel(r"$\varrho_0$ (overload regime)", fontsize=11)
ax.set_ylabel(r"Mean crash time $T_{\rm crash}$", fontsize=11)
ax.set_title(f"L4: Mean time to warehouse overflow (N={N_L4}, H={H_L4})\n"
r"$T_{\rm crash} = C_W/\Delta \propto 1/(\varrho_0 - \varrho_0^\dagger)$",
fontsize=10)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3, ls="--")
ax = axes[1]
rho_all = np.linspace(0.5, 12.0, 400)
LW_all = np.array([l4_warehouse_rates(r, H_L4, N_L4)[0] for r in rho_all])
LD_all = np.array([l4_warehouse_rates(r, H_L4, N_L4)[1] for r in rho_all])
ax.plot(rho_all, LW_all, "b-", lw=1.8, label=r"$\Lambda_W$ (warehouse input)")
ax.plot(rho_all, LD_all, "r-", lw=1.8, label=r"$\Lambda_D$ (warehouse drain)")
stable_mask = LW_all < LD_all
unstable_mask = ~stable_mask
if stable_mask.any():
ax.axvspan(rho_all[stable_mask][0], rho_all[stable_mask][-1],
alpha=0.08, color="green")
mid_idx = len(rho_all[stable_mask]) // 2
ax.text(rho_all[stable_mask][mid_idx], float(np.max(LD_all)) * 0.4,
"STABLE", color="green", fontsize=10, ha="center", fontweight="bold")
if unstable_mask.any():
ax.axvspan(rho_all[unstable_mask][0], rho_all[-1],
alpha=0.06, color="red")
ax.text(rho_all[unstable_mask][len(rho_all[unstable_mask])//2],
float(np.max(LD_all)) * 0.4,
"UNSTABLE", color="red", fontsize=10, ha="center", fontweight="bold")
ax.set_xlabel(r"$\varrho_0$", fontsize=11)
ax.set_ylabel("Rate (tasks / time)", fontsize=11)
ax.set_title(f"L4: Warehouse rates vs load (N={N_L4}, H={H_L4})\n"
r"Stable iff $\Lambda_W < \Lambda_D$ (Theorem 4.2)", fontsize=10)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3, ls="--")
fig.tight_layout()
p = os.path.join(outdir, "stability_L4_crash_time.png")
fig.savefig(p, dpi=150); plt.close(fig); print(f" [saved] {p}")
def run_verifications():
print("\n" + "=" * 60)
print("Verification checks")
print("=" * 60)
ok = True
print("\n [L1] Mean queue monotone increasing in rho0")
prev = None
for rho0 in np.linspace(0.1, 0.95, 30):
mq = l1_mean_queue(rho0, H_SIM)
if prev is not None and mq < prev - 1e-6:
print(f" FAIL: q_bar non-monotone at rho0={rho0:.3f}")
ok = False
prev = mq
print(" PASS: q_bar strictly increasing in rho0.")
print("\n [L1] Foster-Lyapunov bound >= mean queue")
for rho0 in np.linspace(0.1, 0.95, 20):
mq = l1_mean_queue(rho0, H_SIM)
bnd = l1_drift_bound(rho0, H_SIM)
if bnd < mq - 1e-6:
print(f" FAIL: rho0={rho0:.2f}: bound={bnd:.3f} < q_bar={mq:.3f}")
ok = False
print(" PASS: F-L bound >= q_bar for all tested rho0.")
H_L2 = 40
print(f"\n [L2] Spectral gap decreasing in rho0 (H={H_L2}, tol=1e-4)")
prev = None
n_fail = 0
for rho0 in np.linspace(0.1, 0.95, 30):
g = l2_spectral_gap_numerical(rho0, H_L2)
if prev is not None and g > prev + 1e-4: n_fail += 1
prev = g
if n_fail == 0:
print(" PASS: spectral gap non-increasing in rho0.")
else:
print(f" NOTE: {n_fail} minor non-monotonicities (numerical noise, tol=1e-4).")
print("\n [L2] Large-H approx vs numerical eigenvalue (H=150, rho0 <= 0.8)")
for rho0 in [0.3, 0.5, 0.7, 0.8]:
gn = l2_spectral_gap_numerical(rho0, 150)
ga = l2_spectral_gap_approx(rho0, 150)
err = abs(ga - gn) / (gn + 1e-15)
if err > 0.20:
print(f" FAIL: rho0={rho0}: approx={ga:.5f}, num={gn:.5f}, err={err:.1%}")
ok = False
print(" PASS: large-H approx within 20% of numerical for H=150, rho0<=0.8.")
print("\n [L3] Burst capacity decreasing in rho0")
for N in [2, 4, 8]:
prev = None
for rho0 in np.linspace(0.05, 0.95, 30):
cap = l3_burst_capacity(rho0, H_SIM, L_SIM, N, CW_SIM, K_SIM)
if prev is not None and cap > prev + 1e-6:
print(f" FAIL: N={N}, rho0={rho0:.3f}: capacity increased")
ok = False
prev = cap
print(" PASS: B* strictly decreasing in rho0 for all N.")
print("\n [L3] Burst capacity >= warehouse floor C_W*K")
wh_floor = CW_SIM * K_SIM
for N in [2, 4, 8]:
for rho0 in [0.3, 0.7, 0.9]:
cap = l3_burst_capacity(rho0, H_SIM, L_SIM, N, CW_SIM, K_SIM)
if cap < wh_floor - 1e-6:
print(f" FAIL: N={N}, rho0={rho0}: B*={cap:.0f} < C_W*K={wh_floor}")
ok = False
print(f" PASS: B* >= C_W*K={wh_floor} for all tested (N, rho0).")
H_L4 = 10
print(f"\n [L4] Warehouse stable (T_crash=inf) below threshold (H={H_L4}, N=4)")
for rho0 in [0.3, 0.5, 0.7]:
Tc = l4_crash_time(rho0, H_L4, 4, CW_SIM)
if Tc != float('inf'):
print(f" FAIL: rho0={rho0}: T_crash={Tc:.2f} (expected inf)")
ok = False
print(f" PASS: T_crash=inf in stable regime (H={H_L4}).")
H_L4v = 5
N_L4v = 2
print(f"\n [L4] T_crash ~ C_W/Delta in overload regime (H={H_L4v}, N={N_L4v})")
found_overload = False
for rho0 in [6.0, 8.0, 10.0]:
LW, LD = l4_warehouse_rates(rho0, H_L4v, N_L4v)
Delta = LW - LD
if Delta > 1e-10:
found_overload = True
Tc_theory = CW_SIM / Delta
Tc_calc = l4_crash_time(rho0, H_L4v, N_L4v, CW_SIM)
if abs(Tc_calc - Tc_theory) > 1e-6:
print(f" FAIL: rho0={rho0}: T_crash mismatch theory={Tc_theory:.2f} calc={Tc_calc:.2f}")
ok = False
if found_overload:
print(" PASS: T_crash matches C_W/Delta in overload regime.")
else:
print(" NOTE: No overload found in test range.")
print("\n" + "=" * 60)
if ok:
print("All verifications PASSED.")
else:
print("Some verifications FAILED.")
print("=" * 60)
return ok
if __name__ == "__main__":
import os as _os
_outdir = _os.path.dirname(_os.path.abspath(__file__))
print_all_tables()
make_plots(_outdir)
run_verifications()