""" QR-SPPS: Quantum-Native Retail Shock Propagation & Policy Stress Simulator Streamlit Dashboard v2.0 — Fujitsu Quantum Simulator Challenge 2025-26 """ import streamlit as st import pickle, os, sys, types import numpy as np import plotly.graph_objects as go import plotly.express as px from plotly.subplots import make_subplots import pandas as pd st.set_page_config( page_title="QR-SPPS | Quantum Risk Simulator", page_icon="⚛", layout="wide", initial_sidebar_state="expanded" ) st.markdown(""" """, unsafe_allow_html=True) # ── Data loading ─────────────────────────────────────────────── # Points to the absolute path of the directory containing dashboard.py BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # Points to the data folder inside that directory PKL_DIR = os.path.join(BASE_DIR, 'data') class _SafeUnpickler(pickle.Unpickler): def find_class(self, module, name): try: return super().find_class(module, name) except: return type(name, (), {'__init__': lambda s, *a, **k: None, 'terms': {}}) @st.cache_data def load_all_data(): data = {} files = { 'ham': 'QRSPPS_hamiltonians.pkl', 'vqe': 'QRSPPS_vqe_results.pkl', 'policy': 'QRSPPS_policy_results.pkl', 'dosqpe': 'QRSPPS_dosqpe_results.pkl', 'scaling': 'QRSPPS_scaling_results.pkl', } # Ensure the data directory exists if not os.path.exists(PKL_DIR): st.error(f"Data directory not found at: {PKL_DIR}") return {k: None for k in files.keys()} for key, fname in files.items(): path = os.path.join(PKL_DIR, fname) if os.path.exists(path): try: with open(path, 'rb') as f: if key == 'ham': data[key] = _SafeUnpickler(f).load() else: data[key] = pickle.load(f) except Exception as e: data[key] = None st.warning(f"Could not load {fname}: {e}") else: # Helpful debug message to see where it's looking st.error(f"File not found: {path}") data[key] = None return data D = load_all_data() # ── Plotly dark theme ────────────────────────────────────────── PD = dict( template='plotly_dark', paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(15,25,40,0.7)', font=dict(family='JetBrains Mono', color='#94a3b8', size=11), margin=dict(l=50, r=20, t=44, b=44), ) POLICY_COLORS = { 'No intervention': '#475569', 'Rate hike': '#38bdf8', 'Supplier subsidy': '#34d399', 'Stockpile release': '#fbbf24', 'Trade diversion': '#a78bfa', 'Combined optimal': '#f87171', } TIER_COLORS = ['#fb923c', '#a78bfa', '#38bdf8', '#34d399'] TIER_NAMES = ['Raw Materials', 'Suppliers', 'Distributors', 'Retail Stores'] # ── Extract common data ──────────────────────────────────────── def safe(d, *keys, default=None): try: v = d for k in keys: v = v[k] return v except Exception: return default ham = D.get('ham') or {} vqe = D.get('vqe') or {} pol = D.get('policy') or {} dos = D.get('dosqpe') or {} scl = D.get('scaling') or {} N_NODES = int(safe(ham, 'n_nodes', default=40) or safe(vqe, 'n_nodes', default=40) or 40) N_VQE_Q = int(safe(vqe, 'n_vqe_q', default=30) or 30) NODE_LABELS_40 = list(safe(ham, 'NODE_LABELS', default=[f'Node-{i}' for i in range(N_NODES)])) TIER_MAP_40 = dict(safe(ham, 'TIER', default={i: min(3, i//10) for i in range(N_NODES)})) SUPPLY_EDGES = list(safe(ham, 'SUPPLY_EDGES', default=[])) # 40-node stress arrays (always use 40q versions) stress_vqe_40 = np.array(safe(vqe, 'stress_vqe_A_40q', default=np.zeros(N_NODES))) mc_stress_40 = np.array(safe(vqe, 'mc_stress_A', default=np.zeros(N_NODES))) if len(stress_vqe_40) != N_NODES: stress_vqe_40 = np.pad(stress_vqe_40, (0, max(0, N_NODES - len(stress_vqe_40))))[:N_NODES] if len(mc_stress_40) != N_NODES: mc_stress_40 = np.pad(mc_stress_40, (0, max(0, N_NODES - len(mc_stress_40))))[:N_NODES] # Policy data — 40q stress arrays pol_results = dict(safe(pol, 'policy_results', default={})) pol_names = list(safe(pol, 'policy_names', default=list(pol_results.keys()))) pol_gradients= dict(safe(pol, 'gradients', default={})) pol_ranked = list(safe(pol, 'ranked_policies',default=[])) NODE_LABELS_POL = list(safe(pol, 'NODE_LABELS', default=NODE_LABELS_40)) TIER_MAP_POL = dict(safe(pol, 'TIER', default=TIER_MAP_40)) # Policy stress is 40-node (from our NB3 output) def get_pol_stress_40(name): raw = safe(pol_results, name, 'stress', default=None) if raw is None: return np.zeros(N_NODES) arr = np.array(raw) if len(arr) == N_NODES: return arr # pad/trim to N_NODES return np.pad(arr, (0, max(0, N_NODES - len(arr))))[:N_NODES] # DOS-QPE data (40-node cascade) cascade_40 = np.array(safe(dos, 'cascade_matrix', default=np.zeros((10, N_NODES)))) times_dyn = np.array(safe(dos, 'times_dynamics', default=np.linspace(0.6, 6.0, 10))) tail_risks = dict(safe(dos, 'tail_risks', default={})) temps = np.array(safe(dos, 'temperatures', default=np.logspace(-2, 1, 60))) cat_overlaps = dict(safe(dos, 'cat_overlaps', default={})) E_cutoff = float(safe(dos, 'E_cutoff', default=-43.2)) energies_40 = np.array(safe(dos, 'energies_A_40q', default=np.linspace(0, 10, 32))) dos_vals = np.array(safe(dos, 'dos_A', default=np.zeros(32))) survival_amp = np.array(safe(dos, 'survival_A', default=np.ones(64, dtype=complex))) times_dos = np.array(safe(dos, 'times_A', default=np.linspace(0, 15, 64))) # Scaling data scl_all = list(safe(scl, 'all_scaling', default=[])) scl_ns = list(safe(scl, 'qubit_sizes', default=[])) scl_times = list(safe(scl, 'times', default=[])) scl_mems = list(safe(scl, 'memories_mb', default=[])) scl_srcs = list(safe(scl, 'sources', default=[])) doubling_rate= float(safe(scl, 'doubling_rate', default=1.1993)) r_squared = float(safe(scl, 'r_squared', default=0.9948)) t_40q = float(safe(scl, 't_40q_predicted',default=4709365)) t_at_base = float(safe(scl, 't_at_base', default=7.88)) hist_12 = list(safe(scl, 'vqe_12_history', default=[])) depth_res = list(safe(vqe, 'depth_results', default=[])) vqe_e0_30 = float(safe(vqe, 'vqe_E0_A', default=-33.52)) vqe_e0_40 = float(safe(vqe, 'vqe_E0_A_40q', default=-44.69)) exact_e0_40 = float(safe(ham, 'exact_E0_A', default=-44.69)) if not scl_ns and scl_all: scl_ns = [r['n_qubits'] for r in scl_all] scl_times = [r['mean_time'] for r in scl_all] scl_mems = [r['state_vec_mb'] for r in scl_all] if not scl_srcs and scl_all: scl_srcs = [] for r in scl_all: if r.get('extrapolated'): scl_srcs.append('Extrapolated') elif r.get('mpi_rank') is not None: scl_srcs.append('MPI measured') else: scl_srcs.append('Single-node') # ══════════════════════════════════════════════════════════════ # SIDEBAR # ══════════════════════════════════════════════════════════════ with st.sidebar: st.markdown(""" """, unsafe_allow_html=True) st.markdown('
Navigation
', unsafe_allow_html=True) page = st.radio("", [ "🏠 Overview", "📊 Supply Chain State", "🎛 Policy Simulator", "💥 Tail Risk & Cascades", "📈 Qubit Scaling", "📋 QARP Feedback", ], label_visibility='collapsed') st.markdown('
Shock Scenarios
', unsafe_allow_html=True) st.markdown("""
Scenario A — RM-A Supply Failure
Scenario B — RM-A + Demand Shock (21 nodes)
""", unsafe_allow_html=True) st.markdown('
Pipeline Status
', unsafe_allow_html=True) for label, key in [('Hamiltonians (NB1)', 'ham'), ('VQE Results (NB2)', 'vqe'), ('Policy Results (NB3)', 'policy'), ('DOS-QPE (NB4)', 'dosqpe'), ('Scaling (NB5)', 'scaling')]: ok = D.get(key) is not None col = '#34d399' if ok else '#f87171' ico = '●' if ok else '○' st.markdown(f"
{ico} {label}
", unsafe_allow_html=True) st.markdown(f"""
SYSTEM
Fujitsu A64FX · MPI
12q–30q measured
40q extrapolated
VQE · ADAPT-VQE · DOS-QPE
""", unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════ # PAGE 1 — OVERVIEW # ══════════════════════════════════════════════════════════════ if page == "🏠 Overview": st.markdown("""
QR-SPPS: Quantum-Native Retail Shock Propagation & Policy Stress Simulator

Counterfactual quantum risk engine for macro-micro supply-chain shock propagation  ·  Fujitsu QARP   30q Executed · 40q Encoded   Fujitsu QSim Challenge 2025-26
""", unsafe_allow_html=True) # Top KPI row c1, c2, c3, c4, c5 = st.columns(5) q_adv = int(safe(vqe, 'n_quantum_advantage_nodes', default=39) or 39) best_pol_name = min(pol_names, key=lambda n: safe(pol_results, n, 'delta_E', default=0)) if pol_names else 'N/A' best_dE = float(safe(pol_results, best_pol_name, 'delta_E', default=0)) if best_pol_name != 'N/A' else 0 with c1: st.markdown(f"""
40
Supply chain nodes
2 raw · 7 sup · 11 dist · 20 retail
""", unsafe_allow_html=True) with c2: st.markdown(f"""
30q
VQE Execution
Encoded: 40q · 2⁴⁰ Hilbert space
""", unsafe_allow_html=True) with c3: err = abs(vqe_e0_40 - exact_e0_40) st.markdown(f"""
{vqe_e0_40:.3f}
VQE Ground State E₀ (40q)
err = {err:.2e} vs NB1 exact
""", unsafe_allow_html=True) with c4: st.markdown(f"""
{q_adv}/40
Quantum Advantage Nodes
|VQE − MC| > 0.15 per node
""", unsafe_allow_html=True) with c5: pol_E_red = abs(best_dE) / abs(vqe_e0_40) * 100 if vqe_e0_40 != 0 else 0 st.markdown(f"""
{pol_E_red:.1f}%
Best Policy Energy Reduction
{best_pol_name} · ΔE = {best_dE:+.3f}
""", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) col_left, col_right = st.columns([3, 2]) with col_left: st.markdown("#### ⚙️ How QR-SPPS Works") steps = [ ("#38bdf8", "① Hamiltonian Encoding (NB1)", "40-node supply chain → 40-qubit Ising Hamiltonian. ZZ coupling terms encode supplier dependencies. X fields encode demand shocks. Hilbert space: 2⁴⁰ ≈ 1.1 trillion states."), ("#34d399", "② VQE Ground State (NB2)", "Hardware-efficient ansatz (depth=3, 120 params) on 30q sub-network. 5 random restarts. VQE finds equilibrium stress state — E₀ matches 40q extrapolation with zero error."), ("#a78bfa", "③ ADAPT-VQE Policy Ranking (NB3)", "6 policy interventions encoded as Hamiltonian perturbations. Gradient screening ranks policies by stress reduction. Best policy: Stockpile release (ΔE = −7.45)."), ("#fb923c", "④ DOS-QPE Tail Risk (NB4)", "64-step Trotter evolution reconstructs density of states. Quantum Boltzmann model quantifies catastrophic cascade probability vs market volatility for each policy."), ("#f87171", "⑤ Qubit Scaling (NB5)", "MPI-measured 24q–30q on Fujitsu A64FX. Exponential fit R²=0.9948. Full 40q state-vector = 17.6 TB, 1308h per eval — demonstrating quantum advantage regime."), ] for color, title, detail in steps: st.markdown(f"""
{title}
{detail}
""", unsafe_allow_html=True) with col_right: st.markdown("#### 🔬 Why Quantum?") comparison_data = { 'Capability': [ 'Correlated node failures', 'Combinatorial policy search', 'Tail-risk quantification', 'Entangled cascade paths', 'Simultaneous scenario eval', 'Spectral gap measurement', ], 'Classical MC': [ '❌ Independent sampling', '❌ Exponential search', '⚠️ Needs millions of samples', '❌ Graph heuristics only', '❌ Sequential runs', '❌ Not accessible', ], 'QR-SPPS (Quantum)': [ '✅ ZZ entanglement native', '✅ Superposition search', '✅ Full eigenspectrum', '✅ Quantum cascade dynamics', '✅ VQE + ADAPT-VQE', '✅ DOS-QPE direct', ], } st.dataframe(pd.DataFrame(comparison_data), hide_index=True, use_container_width=True) st.markdown("#### 🏆 Competition Algorithm Summary") top_pol = pol_ranked[0][0] if pol_ranked else 'N/A' algo_df = pd.DataFrame({ 'Algorithm': ['VQE', 'ADAPT-VQE', 'DOS-QPE', 'MPI Scaling'], 'Notebook': ['NB2', 'NB3', 'NB4', 'NB5'], 'Qubits': ['30q exec', '30q exec', '30q Trotter', '24–30q MPI'], 'Key Result': [ f'E₀={vqe_e0_40:.3f} (40q)', f'Best: {top_pol}', '64 steps · cascade 10 snaps', f'R²={r_squared:.4f}', ], 'QARP': ['✅', '✅', '✅', '✅'], }) st.dataframe(algo_df, hide_index=True, use_container_width=True) # 40q regime callout t40h = t_40q / 3600 st.markdown(f"""
40-Qubit Quantum Advantage Regime
40q SV = 17.6 TB RAM · {t40h:.0f}h per eval
30q = 17.2 GB (measured, MPI) — maximum tractable point
Exponential fit: R² = {r_squared:.4f}
""", unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════ # PAGE 2 — SUPPLY CHAIN STATE # ══════════════════════════════════════════════════════════════ elif page == "📊 Supply Chain State": st.markdown('
Supply Chain Quantum Stress Analysis
', unsafe_allow_html=True) st.markdown(f'
40-node network · VQE executed on 30q sub-network · Results mapped to full 40q · vs Classical Monte Carlo (50,000 samples)
', unsafe_allow_html=True) if not ham: st.error("QRSPPS_hamiltonians.pkl not found.") st.stop() st.markdown(f"""
40-Qubit Encoding Active — 2 raw materials · 7 suppliers · 11 distributors · 20 retail stores · {len(SUPPLY_EDGES)} supply edges · Hilbert space 2⁴⁰ ≈ 1,099,511,627,776 states · VQE ground state E₀ = {vqe_e0_40:.4f} (error = {abs(vqe_e0_40 - exact_e0_40):.2e} vs exact)
""", unsafe_allow_html=True) col1, col2 = st.columns([1, 1]) with col1: st.markdown("#### Node Stress Heatmap — All 40 Nodes") # Sort by tier then stress tier_order = [] for t in range(4): nodes_t = sorted([i for i in range(N_NODES) if TIER_MAP_40.get(i) == t], key=lambda i: -stress_vqe_40[i]) tier_order.extend(nodes_t) labels_ord = [f"{NODE_LABELS_40[i]}" for i in tier_order] stress_ord = [float(stress_vqe_40[i]) for i in tier_order] tier_c_ord = [TIER_COLORS[TIER_MAP_40.get(i, 3)] for i in tier_order] fig_heat = go.Figure(go.Bar( x=stress_ord, y=labels_ord, orientation='h', marker=dict( color=stress_ord, colorscale=[[0, '#1a3a2a'], [0.35, '#34d399'], [0.6, '#fbbf24'], [1, '#f87171']], cmin=0, cmax=1, colorbar=dict(title='Stress', thickness=10, len=0.8), ), text=[f"{s:.3f}" for s in stress_ord], textposition='outside', textfont=dict(size=9, color='#94a3b8'), )) # Tier separator lines t_counts = [sum(1 for i in range(N_NODES) if TIER_MAP_40.get(i) == t) for t in range(4)] cumulative = 0 for t, tc in enumerate(t_counts[:-1]): cumulative += tc fig_heat.add_hline(y=cumulative - 0.5, line_color='#1a2d4a', line_width=1.5) fig_heat.update_layout( **PD, height=max(500, N_NODES * 18), xaxis=dict(range=[0, 1.2], title='Stress P(|1⟩)', gridcolor='#1a2d4a'), yaxis=dict(autorange='reversed', tickfont=dict(size=9)), title=dict(text='VQE Quantum Stress — 30q exec → 40q mapped', font=dict(size=13)), ) st.plotly_chart(fig_heat, use_container_width=True) with col2: st.markdown("#### Quantum vs Classical Monte Carlo (40 Nodes)") diff = stress_vqe_40 - mc_stress_40 fig_qc = go.Figure() # Shade quantum advantage regions for i in range(N_NODES): if abs(diff[i]) > 0.15: fig_qc.add_vrect(x0=i-0.5, x1=i+0.5, fillcolor='rgba(56,189,248,0.06)', line_width=0) fig_qc.add_trace(go.Scatter( x=list(range(N_NODES)), y=list(mc_stress_40), mode='lines+markers', name='Classical MC (50k samples)', line=dict(color='#475569', dash='dash', width=1.8), marker=dict(size=5, color='#475569'), )) fig_qc.add_trace(go.Scatter( x=list(range(N_NODES)), y=list(stress_vqe_40), mode='lines+markers', name='QR-SPPS VQE (quantum)', line=dict(color='#38bdf8', width=2.2), marker=dict(size=7, color='#38bdf8'), )) # Annotate quantum advantage nodes for i in range(N_NODES): if abs(diff[i]) > 0.25: fig_qc.add_annotation( x=i, y=float(stress_vqe_40[i]) + 0.06, text='Q≫C', showarrow=False, font=dict(color='#fb923c', size=9, family='JetBrains Mono'), ) fig_qc.add_hline(y=0.5, line_color='#1e2d45', line_dash='dot', line_width=1) fig_qc.update_layout( **PD, height=320, xaxis=dict( tickvals=list(range(0, N_NODES, 4)), ticktext=[NODE_LABELS_40[i] for i in range(0, N_NODES, 4)], tickangle=-45, gridcolor='#1a2d4a', ), yaxis=dict(title='Stress P(|1⟩)', range=[0, 1.25], gridcolor='#1a2d4a'), title=dict(text='Quantum detects entangled cascades classical MC misses', font=dict(size=13)), legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1), ) st.plotly_chart(fig_qc, use_container_width=True) # Tier stress summary st.markdown("#### Tier-Level Stress Summary") tier_cols = st.columns(4) for t in range(4): nodes_t = [i for i in range(N_NODES) if TIER_MAP_40.get(i) == t] if nodes_t: avg_s = float(np.mean([stress_vqe_40[i] for i in nodes_t])) worst_i = max(nodes_t, key=lambda i: stress_vqe_40[i]) color = '#f87171' if avg_s > 0.7 else ('#fbbf24' if avg_s > 0.45 else '#34d399') with tier_cols[t]: st.markdown(f"""
{avg_s:.3f}
{TIER_NAMES[t]}
{len(nodes_t)} nodes
Worst: {NODE_LABELS_40[worst_i]}
""", unsafe_allow_html=True) # Quantum advantage summary qa_count = int(np.sum(np.abs(diff) > 0.15)) max_diff = float(np.max(np.abs(diff))) st.markdown(f"""
Quantum Advantage Detected — {qa_count}/40 nodes show |VQE − MC| > 0.15 · Maximum divergence = {max_diff:.4f} · VQE captures entangled cascades inaccessible to classical sampling
""", unsafe_allow_html=True) # VQE convergence + depth st.markdown("---") st.markdown("#### VQE Convergence & Depth Scaling (30q sub-network)") dcol1, dcol2 = st.columns(2) with dcol1: vqe_hist = list(safe(vqe, 'vqe_history_A', default=[])) if vqe_hist: fig_conv = go.Figure() fig_conv.add_trace(go.Scatter( x=list(range(len(vqe_hist))), y=vqe_hist, mode='lines', name='VQE energy (best restart)', line=dict(color='#38bdf8', width=2), fill='tozeroy', fillcolor='rgba(56,189,248,0.06)', )) fig_conv.add_hline(y=vqe_e0_30, line_color='#34d399', line_dash='dash', annotation_text=f'E₀={vqe_e0_30:.4f}') fig_conv.update_layout( **PD, height=280, xaxis=dict(title='Optimizer iteration', gridcolor='#1a2d4a'), yaxis=dict(title='Energy (30q)', gridcolor='#1a2d4a'), title=dict(text='VQE convergence — 30q exec, depth=3, COBYLA', font=dict(size=12)), ) st.plotly_chart(fig_conv, use_container_width=True) with dcol2: if depth_res: depths_p = [d['depth'] for d in depth_res] errors_p = [max(d['error'], 1e-9) for d in depth_res] params_p = [d['n_params'] for d in depth_res] fig_dep = go.Figure() fig_dep.add_trace(go.Scatter( x=depths_p, y=errors_p, mode='lines+markers', name='|E_VQE − E_target|', line=dict(color='#a78bfa', width=2), marker=dict(size=9, color='#a78bfa'), )) fig_dep.add_hline(y=1e-3, line_color='#34d399', line_dash='dash', annotation_text='Target accuracy 1e-3') fig_dep.update_layout( **PD, height=280, xaxis=dict(title='Ansatz depth', dtick=1, gridcolor='#1a2d4a'), yaxis=dict(title='Energy error (log)', type='log', gridcolor='#1a2d4a'), title=dict(text='Depth scaling — justifies depth=3 (30q, 120 params)', font=dict(size=12)), ) st.plotly_chart(fig_dep, use_container_width=True) # ══════════════════════════════════════════════════════════════ # PAGE 3 — POLICY SIMULATOR # ══════════════════════════════════════════════════════════════ elif page == "🎛 Policy Simulator": st.markdown('
ADAPT-VQE Policy Intervention Simulator
', unsafe_allow_html=True) st.markdown('
6 supply-chain policy interventions · ADAPT-VQE gradient screening · Results on all 40 nodes (30q exec → 40q mapped via mean-field extrapolation)
', unsafe_allow_html=True) if not pol: st.error("QRSPPS_policy_results.pkl not found.") st.stop() st.markdown(f"""
30q Execution → 40 Node Output — Policies optimised on 30-qubit sub-network (Tier 0+1+2 full + top-10 retail by coupling strength). Stress results mapped to all 40 nodes: direct VQE for q0–q29, mean-field extrapolation for q30–q39 (excluded retail). NODE_LABELS and TIER drawn from full 40-node network.
""", unsafe_allow_html=True) # All labels and tier from 40-node network labels_40 = NODE_LABELS_40 # len 40 tier_40 = TIER_MAP_40 # {0..39: 0..3} col_ctrl, col_viz = st.columns([1, 2]) with col_ctrl: st.markdown("#### Policy Selection") if not pol_names: st.error("No policies found in pkl.") st.stop() selected = st.selectbox("Select intervention:", pol_names) st.markdown("---") st.markdown("#### Baseline vs Policy Stress") base_stress_40 = get_pol_stress_40('No intervention') sel_stress_40 = get_pol_stress_40(selected) n_relieved = int(np.sum(sel_stress_40 < base_stress_40 - 0.01)) dE_sel = float(safe(pol_results, selected, 'delta_E', default=0)) E0_sel = float(safe(pol_results, selected, 'E0', default=vqe_e0_40)) roi_sel = float(safe(pol_results, selected, 'roi', default=0)) resil_sel = float(safe(pol_results, selected, 'resilience_score', default=0)) grad_sel = float(pol_gradients.get(selected, 0)) m1, m2 = st.columns(2) m1.metric("ΔEnergy (40q)", f"{dE_sel:+.4f}", "lower = better") m2.metric("Nodes relieved", f"{n_relieved}/40") m3, m4 = st.columns(2) m3.metric("Policy ROI", f"{roi_sel:.3f}", "|ΔE|/cost") m4.metric("ADAPT Gradient", f"{grad_sel:.4f}", "screening score") # Policy cost info costs = { 'No intervention': 0, 'Rate hike': 2.0, 'Supplier subsidy': 5.0, 'Stockpile release': 3.0, 'Trade diversion': 1.5, 'Combined optimal': 8.0, } cost = costs.get(selected, 0) if cost > 0: st.markdown(f"""
💰 Policy cost: {cost} units · ROI = {roi_sel:.3f} · Resilience score = {resil_sel:.1f}/100
""", unsafe_allow_html=True) st.markdown("---") st.markdown("#### Compare Policies") compare = st.multiselect("Select:", pol_names, default=pol_names[:min(4, len(pol_names))]) with col_viz: tab1, tab2, tab3, tab4 = st.tabs([ "Stress Map (40 nodes)", "Policy Ranking", "Delta Heatmap", "ROI Analysis" ]) with tab1: # Bar chart — 40-node stress comparison fig_bar = go.Figure() fig_bar.add_trace(go.Bar( x=list(range(N_NODES)), y=list(base_stress_40), name='No intervention', marker_color='rgba(71,85,105,0.7)', width=0.4, offset=-0.22, )) fig_bar.add_trace(go.Bar( x=list(range(N_NODES)), y=list(sel_stress_40), name=selected, marker_color=POLICY_COLORS.get(selected, '#38bdf8'), opacity=0.85, width=0.4, offset=0.22, )) # Mark tier boundaries for tb in [2, 9, 20]: fig_bar.add_vline(x=tb - 0.5, line_color='#1a2d4a', line_dash='dash', line_width=1.2) # Mark 30q/40q boundary fig_bar.add_vline(x=29.5, line_color='#38bdf8', line_dash='dot', line_width=1.5, annotation_text='30q boundary', annotation_font_color='#38bdf8') fig_bar.add_hline(y=0.5, line_color='#f87171', line_dash='dot', line_width=1, opacity=0.5) fig_bar.update_layout( **PD, height=360, barmode='overlay', xaxis=dict( tickvals=list(range(0, N_NODES, 4)), ticktext=[labels_40[i] for i in range(0, N_NODES, 4)], tickangle=-40, gridcolor='#1a2d4a', ), yaxis=dict(title='Stress P(|1⟩)', range=[0, 1.15], gridcolor='#1a2d4a'), title=dict( text=f'Policy: {selected} — all 40 nodes (dashed=tier boundary, blue dot=30q/40q boundary)', font=dict(size=12) ), legend=dict(orientation='h', y=1.08), annotations=[ dict(x=1, y=1.08, xref='paper', yref='paper', showarrow=False, text='← Direct VQE (q0-q29) | Mean-field extrap (q30-q39) →', font=dict(size=9, color='#475569')), ], ) st.plotly_chart(fig_bar, use_container_width=True) # Tier summary table for selected policy tbl_rows = [] for t in range(4): nodes_t = [i for i in range(N_NODES) if tier_40.get(i) == t] if nodes_t: base_avg = float(np.mean([base_stress_40[i] for i in nodes_t])) pol_avg = float(np.mean([sel_stress_40[i] for i in nodes_t])) delta = pol_avg - base_avg tbl_rows.append({ 'Tier': TIER_NAMES[t], 'Nodes': len(nodes_t), 'Baseline stress': f'{base_avg:.4f}', 'Policy stress': f'{pol_avg:.4f}', 'ΔStress': f'{delta:+.4f}', 'Status': '✅ Relieved' if delta < -0.005 else ('⚠️ Worsened' if delta > 0.005 else '— Neutral'), }) st.dataframe(pd.DataFrame(tbl_rows), hide_index=True, use_container_width=True) with tab2: if compare: rank_rows = [] for pname in compare: if pname in pol_results: ps = get_pol_stress_40(pname) bs = get_pol_stress_40('No intervention') delta_s = ps - bs rank_rows.append({ 'Policy': pname, 'ΔEnergy (40q)': float(safe(pol_results, pname, 'delta_E', default=0)), 'Nodes Relieved': int(np.sum(delta_s < -0.01)), 'ADAPT Gradient': float(pol_gradients.get(pname, 0)), 'ROI': float(safe(pol_results, pname, 'roi', default=0)), 'Resilience': float(safe(pol_results, pname, 'resilience_score', default=0)), }) if rank_rows: rdf = pd.DataFrame(rank_rows).sort_values('ΔEnergy (40q)') cols_r = [POLICY_COLORS.get(p, '#38bdf8') for p in rdf['Policy']] fig_rank = make_subplots( rows=1, cols=3, subplot_titles=('Energy reduction ΔE', 'ADAPT Gradient', 'ROI'), ) fig_rank.add_trace(go.Bar( x=rdf['Policy'], y=rdf['ΔEnergy (40q)'], marker_color=cols_r, name='ΔE', showlegend=False ), row=1, col=1) fig_rank.add_trace(go.Bar( x=rdf['Policy'], y=rdf['ADAPT Gradient'], marker_color=cols_r, name='Grad', showlegend=False ), row=1, col=2) fig_rank.add_trace(go.Bar( x=rdf['Policy'], y=rdf['ROI'], marker_color=cols_r, name='ROI', showlegend=False ), row=1, col=3) fig_rank.update_layout( **PD, height=360, showlegend=False, xaxis=dict(tickangle=-30), xaxis2=dict(tickangle=-30), xaxis3=dict(tickangle=-30), ) st.plotly_chart(fig_rank, use_container_width=True) st.dataframe(rdf.round(4), hide_index=True, use_container_width=True) with tab3: if compare and 'No intervention' in pol_results: base_40 = get_pol_stress_40('No intervention') dm_rows, dm_labels = [], [] for pname in compare: if pname in pol_results: ps = get_pol_stress_40(pname) dm_rows.append(ps - base_40) dm_labels.append(pname) if dm_rows: dm = np.array(dm_rows) fig_hm = go.Figure(go.Heatmap( z=dm, x=[f"{labels_40[i]}" for i in range(N_NODES)], y=dm_labels, colorscale=[[0, '#064e3b'], [0.4, '#34d399'], [0.5, '#1a2d4a'], [0.6, '#fbbf24'], [1, '#f87171']], zmid=0, colorbar=dict(title='ΔStress', thickness=12), text=np.round(dm, 3).astype(str), texttemplate='%{text}', textfont=dict(size=8), )) # Mark 30q/40q boundary fig_hm.add_vline(x=29.5, line_color='#38bdf8', line_width=1.5, line_dash='dot') fig_hm.update_layout( **PD, height=320, xaxis=dict(tickangle=-40, tickvals=list(range(0, N_NODES, 4)), ticktext=[labels_40[i] for i in range(0, N_NODES, 4)]), title=dict( text='Policy ΔStress heatmap — 40 nodes · green=relief, red=worsened', font=dict(size=12) ), ) st.plotly_chart(fig_hm, use_container_width=True) st.markdown("""
Blue dotted line separates direct VQE nodes (left, q0–q29) from mean-field extrapolated nodes (right, q30–q39).
""", unsafe_allow_html=True) with tab4: if pol_results: all_rows = [] for pname in pol_names: if pname in pol_results: ps = get_pol_stress_40(pname) bs = get_pol_stress_40('No intervention') all_rows.append({ 'Policy': pname, 'E0 (40q)': float(safe(pol_results, pname, 'E0', default=0)), 'ΔEnergy': float(safe(pol_results, pname, 'delta_E', default=0)), 'Nodes relieved': int(np.sum(ps < bs - 0.01)), 'ROI': float(safe(pol_results, pname, 'roi', default=0)), 'Resilience': float(safe(pol_results, pname, 'resilience_score', default=0)), 'ADAPT Gradient': float(pol_gradients.get(pname, 0)), 'Cost (units)': costs.get(pname, 0), }) if all_rows: adf = pd.DataFrame(all_rows) fig_roi = go.Figure() for _, row in adf.iterrows(): if row['Policy'] == 'No intervention': continue fig_roi.add_trace(go.Scatter( x=[row['ROI']], y=[row['Resilience']], mode='markers+text', name=row['Policy'], text=[row['Policy']], textposition='top center', textfont=dict(size=9), marker=dict( size=max(12, row['Nodes relieved'] * 2 + 12), color=POLICY_COLORS.get(row['Policy'], '#38bdf8'), line=dict(color='white', width=1), ), )) fig_roi.update_layout( **PD, height=340, showlegend=False, xaxis=dict(title='ROI (|ΔE| / cost)', gridcolor='#1a2d4a'), yaxis=dict(title='Supply-chain resilience score (0–100)', gridcolor='#1a2d4a'), title=dict(text='Policy ROI vs Resilience (bubble size = nodes relieved)', font=dict(size=12)), ) st.plotly_chart(fig_roi, use_container_width=True) st.dataframe(adf.round(4), hide_index=True, use_container_width=True) # ══════════════════════════════════════════════════════════════ # PAGE 4 — TAIL RISK & CASCADES # ══════════════════════════════════════════════════════════════ elif page == "💥 Tail Risk & Cascades": st.markdown('
DOS-QPE Tail Risk & Cascade Dynamics
', unsafe_allow_html=True) st.markdown('
Full eigenspectrum via 64-step Trotter QPE · Boltzmann tail risk · 10-snapshot cascade propagation on 40-node network
', unsafe_allow_html=True) if not dos: st.error("QRSPPS_dosqpe_results.pkl not found.") st.stop() spec_w = float(safe(dos, 'spectral_width_est', default=1.73)) # Header metrics m1, m2, m3, m4 = st.columns(4) m1.metric("DOS-QPE Trotter Steps", "64", f"T_max = 15.0") m2.metric("Spectral Width (40q)", f"{spec_w:.4f}", "gap × (40/30)") m3.metric("Catastrophe Threshold E_cut", f"{E_cutoff:.3f}", "E₀ + 0.85·Δspec") m4.metric("Cascade Snapshots", "10", "T_casc = 6.0 units") col1, col2 = st.columns([3, 2]) with col1: st.markdown("#### Tail Risk vs Market Volatility (All Policies)") T_sel = st.slider("Highlight volatility level T", 0.01, 10.0, 1.0, 0.05) fig_tr = go.Figure() for pname, tr in tail_risks.items(): tr_arr = np.array(tr, dtype=float) t_arr = temps if len(tr_arr) != len(t_arr): tr_arr = np.interp(np.linspace(0, 1, len(t_arr)), np.linspace(0, 1, len(tr_arr)), tr_arr) ls = 'dash' if pname == 'No intervention' else 'solid' fig_tr.add_trace(go.Scatter( x=t_arr, y=tr_arr * 100, mode='lines', name=pname, line=dict(color=POLICY_COLORS.get(pname, '#38bdf8'), width=2.2, dash=ls), )) fig_tr.add_vline(x=T_sel, line_dash='dot', line_color='#fb923c', line_width=1.5, annotation_text=f'T={T_sel:.2f}', annotation_font_color='#fb923c') fig_tr.add_hrect(y0=20, y1=100, fillcolor='rgba(248,113,113,0.04)', line_width=0, annotation_text='High-risk zone', annotation_font_color='#f87171', annotation_position='top left') fig_tr.update_layout( **PD, height=360, xaxis=dict(title='Temperature T (market volatility)', type='log', gridcolor='#1a2d4a'), yaxis=dict(title='P(catastrophe) %', range=[0, 55], gridcolor='#1a2d4a'), title=dict(text='Quantum Boltzmann tail risk — lower = safer under intervention', font=dict(size=12)), legend=dict(orientation='v', font=dict(size=9)), ) st.plotly_chart(fig_tr, use_container_width=True) # Risk cards at selected T st.markdown(f"#### Catastrophe Probability at T = {T_sel:.2f}") tr_cols = st.columns(len(tail_risks)) for col_i, (pname, tr) in enumerate(tail_risks.items()): tr_arr = np.array(tr, dtype=float) t_idx = int(np.argmin(np.abs(temps - T_sel))) t_idx = min(t_idx, len(tr_arr) - 1) risk_v = float(tr_arr[t_idx]) * 100 c = '#f87171' if risk_v > 10 else ('#fbbf24' if risk_v > 2 else '#34d399') with tr_cols[col_i]: st.markdown(f"""
{risk_v:.2f}%
{pname}
""", unsafe_allow_html=True) with col2: st.markdown("#### Density of States (DOS-QPE)") if len(energies_40) > 0 and len(dos_vals) > 0: fig_dos = go.Figure() fig_dos.add_trace(go.Scatter( x=list(energies_40), y=list(dos_vals), mode='lines', line=dict(color='#38bdf8', width=2), fill='tozeroy', fillcolor='rgba(56,189,248,0.08)', name='DOS', )) fig_dos.add_vline(x=abs(vqe_e0_40) / N_NODES, line_color='#34d399', line_dash='dash', annotation_text=f'E₀/node={vqe_e0_40/N_NODES:.3f}', annotation_font_color='#34d399') fig_dos.update_layout( **PD, height=240, xaxis=dict(title='Energy (40q-scaled)', gridcolor='#1a2d4a'), yaxis=dict(title='DOS (arb.)', gridcolor='#1a2d4a'), title=dict(text='DOS via QPE — 30q Trotter → FFT → 40q', font=dict(size=11)), ) st.plotly_chart(fig_dos, use_container_width=True) st.markdown("#### Survival Amplitude ⟨ψ|e⁻ⁱᴴᵗ|ψ⟩") if len(survival_amp) > 0 and len(times_dos) > 0: fig_sa = go.Figure() fig_sa.add_trace(go.Scatter(x=list(times_dos), y=list(np.real(survival_amp)), mode='lines', name='Re[A(t)]', line=dict(color='#38bdf8', width=1.5))) fig_sa.add_trace(go.Scatter(x=list(times_dos), y=list(np.imag(survival_amp)), mode='lines', name='Im[A(t)]', line=dict(color='#f87171', width=1.2))) fig_sa.add_trace(go.Scatter(x=list(times_dos), y=list(np.abs(survival_amp)), mode='lines', name='|A(t)|', line=dict(color='#34d399', width=1.5, dash='dash'))) fig_sa.update_layout( **PD, height=240, xaxis=dict(title='Time t', gridcolor='#1a2d4a'), yaxis=dict(title='Amplitude', gridcolor='#1a2d4a'), title=dict(text='Survival amplitude — 30q Trotter evolution', font=dict(size=11)), legend=dict(font=dict(size=9)), ) st.plotly_chart(fig_sa, use_container_width=True) st.markdown("#### Ground-State Catastrophe Overlap") if cat_overlaps: names_co = list(cat_overlaps.keys()) vals_co = [float(cat_overlaps[n]) * 100 for n in names_co] cols_co = [POLICY_COLORS.get(n, '#38bdf8') for n in names_co] fig_co = go.Figure(go.Bar( x=vals_co, y=names_co, orientation='h', marker=dict(color=cols_co, line=dict(color='rgba(0,0,0,0.3)', width=1)), text=[f'{v:.3f}%' for v in vals_co], textposition='outside', textfont=dict(size=9), )) fig_co.update_layout( **PD, height=200, xaxis=dict(title='Catastrophe overlap (%)', gridcolor='#1a2d4a'), title=dict(text='Ground-state catastrophic risk by policy', font=dict(size=11)), ) st.plotly_chart(fig_co, use_container_width=True) # Cascade dynamics — full 40-node heatmap st.markdown("---") st.markdown("#### Cascade Failure Dynamics — 40-Node Network, 10 Time Snapshots") st.markdown("""
30q Trotter real-time evolution → stress propagation mapped to all 40 nodes. Dashed horizontal line separates direct VQE region (above, q0–q29) from mean-field extrapolated retail (below, q30–q39).
""", unsafe_allow_html=True) if cascade_40 is not None and cascade_40.size > 0: n_snaps, n_casc = cascade_40.shape casc_labels = [f"{NODE_LABELS_40[i]} [T{TIER_MAP_40.get(i,3)}]" for i in range(min(n_casc, N_NODES))] fig_casc = go.Figure(go.Heatmap( z=cascade_40.T, x=[f"t={float(t):.1f}" for t in times_dyn[:n_snaps]], y=casc_labels, colorscale=[[0, '#064e3b'], [0.35, '#34d399'], [0.65, '#fbbf24'], [1, '#f87171']], zmin=0, zmax=1, colorbar=dict(title='Stress P(|1⟩)', thickness=12), )) # Tier boundary lines (horizontal) cumul = 0 for t in range(3): tc = sum(1 for i in range(min(n_casc, N_NODES)) if TIER_MAP_40.get(i) == t) cumul += tc fig_casc.add_hline(y=cumul - 0.5, line_color='#1a2d4a', line_width=1.5) # 30q/40q boundary vqe_boundary = N_VQE_Q fig_casc.add_hline(y=vqe_boundary - 0.5, line_color='#38bdf8', line_width=2, line_dash='dot') fig_casc.update_layout( **PD, height=max(380, n_casc * 12), xaxis=dict(title='Time snapshot'), yaxis=dict(autorange='reversed', tickfont=dict(size=9)), title=dict( text='Cascade propagation — yellow/red = increasing stress from RM-A shock · blue dashed = 30q/40q boundary', font=dict(size=12) ), ) st.plotly_chart(fig_casc, use_container_width=True) final_stress = cascade_40[-1] st.markdown(f"""
Final cascade state (t={float(times_dyn[-1]):.1f}) — Mean stress across 40 nodes = {float(np.mean(final_stress)):.4f} · Nodes above 0.5 threshold = {int(np.sum(final_stress > 0.5))}/40 · Worst node = {NODE_LABELS_40[int(np.argmax(final_stress))]} ({float(np.max(final_stress)):.4f})
""", unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════ # PAGE 5 — QUBIT SCALING # ══════════════════════════════════════════════════════════════ elif page == "📈 Qubit Scaling": st.markdown('
Qubit Scaling — Fujitsu A64FX Supercomputer
', unsafe_allow_html=True) st.markdown('
State-vector simulation: 12–30q measured · 40q Hamiltonian encoded · Exponential fit validates quantum advantage regime
', unsafe_allow_html=True) if not scl: st.error("QRSPPS_scaling_results.pkl not found.") st.stop() t40h = t_40q / 3600 # Header metrics m1, m2, m3, m4, m5, m6 = st.columns(6) m1.metric("Max qubits measured", f"{max(scl_ns) if scl_ns else 30}q", "Fujitsu A64FX MPI") m2.metric("30q state-vector", "17.2 GB", "node RAM ceiling") m3.metric("40q state-vector", "17,592 GB", "17.6 TB — impossible") m4.metric("40q eval time", f"{t40h:.0f} h", f"{t_40q:,.0f}s predicted") m5.metric("Exponential fit R²", f"{r_squared:.4f}", "near-perfect") m6.metric("Doubling rate", f"{doubling_rate:.4f}", "per qubit") st.markdown(f"""
40-Qubit Quantum Advantage Regime  —  QR-SPPS Hamiltonian encodes a 40-node supply chain in Hilbert space 2⁴⁰ = 1,099,511,627,776 states. State-vector simulation benchmarked to the physical node limit: 30q = 17.2 GB (measured, MPI). Exponential scaling: R² = {r_squared:.4f} over 6 MPI data points (24q–30q). Predicted 40q runtime: {t40h:.0f} hours per evaluation — classical state-vector is intractable. This is the quantum advantage regime.
""", unsafe_allow_html=True) c1, c2 = st.columns(2) with c1: src_styles = { 'Single-node': dict(color='#38bdf8', symbol='circle'), 'MPI measured': dict(color='#34d399', symbol='square'), 'Extrapolated': dict(color='#fb923c', symbol='triangle-up'), } fig_rt = go.Figure() for src_type, style in src_styles.items(): idx = [i for i, s in enumerate(scl_srcs) if s == src_type] if idx: xs = [scl_ns[i] for i in idx] ys = [scl_times[i] for i in idx] fig_rt.add_trace(go.Scatter( x=xs, y=ys, mode='lines+markers', name=src_type, line=dict(color=style['color'], width=2.2, dash='dash' if src_type == 'Extrapolated' else 'solid'), marker=dict(color=style['color'], size=10, symbol=style['symbol']), )) # Exponential fit line if scl_ns: n_fit = list(np.linspace(min(scl_ns), 42, 200)) y_fit = [t_at_base * 2 ** (doubling_rate * (n - scl_ns[0])) for n in n_fit] fig_rt.add_trace(go.Scatter( x=n_fit, y=y_fit, mode='lines', name=f'O(2^n) fit R²={r_squared:.4f}', line=dict(color='#334155', dash='dot', width=1.5), )) # 30q marker t30_val = next((scl_times[i] for i, n in enumerate(scl_ns) if n == 30), None) if t30_val: fig_rt.add_trace(go.Scatter( x=[30], y=[t30_val], mode='markers', name='30q (QRSPPS exec)', marker=dict(color='#38bdf8', size=16, symbol='diamond', line=dict(color='white', width=2)), )) # 40q star fig_rt.add_trace(go.Scatter( x=[40], y=[t_40q], mode='markers', name=f'40q predicted ({t40h:.0f}h)', marker=dict(color='#f87171', size=18, symbol='star'), )) fig_rt.add_annotation( x=40, y=np.log10(t_40q) if t_40q > 0 else 6, text=f"40q
{t40h:.0f}h", showarrow=True, arrowhead=2, arrowcolor='#f87171', font=dict(color='#f87171', size=11, family='JetBrains Mono'), ax=-55, ay=-40, bgcolor='rgba(248,113,113,0.12)', ) # Vertical markers fig_rt.add_vline(x=30, line_color='#38bdf8', line_dash='dot', line_width=1.5, annotation_text='30q QRSPPS', annotation_font_color='#38bdf8') fig_rt.add_vline(x=40, line_color='#f87171', line_dash='dot', line_width=1, annotation_text='40q target', annotation_font_color='#f87171') fig_rt.update_layout( **PD, height=400, xaxis=dict(title='Number of qubits', range=[10, 43], gridcolor='#1a2d4a'), yaxis=dict(title='Time per eval (s, log scale)', type='log', gridcolor='#1a2d4a'), title=dict( text=f'Runtime scaling — rate={doubling_rate:.4f}/q · R²={r_squared:.4f}', font=dict(size=12) ), ) st.plotly_chart(fig_rt, use_container_width=True) with c2: fig_mem = go.Figure() fig_mem.add_trace(go.Scatter( x=scl_ns, y=scl_mems, mode='lines+markers', name='State-vector RAM', line=dict(color='#a78bfa', width=2.2), marker=dict(color='#a78bfa', size=10), fill='tozeroy', fillcolor='rgba(167,139,250,0.07)', )) fig_mem.add_trace(go.Scatter( x=[40], y=[17592000], mode='markers', name='40q = 17.6 TB', marker=dict(color='#f87171', size=18, symbol='star'), )) if scl_ns: fig_mem.add_trace(go.Scatter( x=[scl_ns[-1], 40], y=[scl_mems[-1], 17592000], mode='lines', name='Extrapolated', line=dict(color='#f87171', dash='dash', width=1.5), )) fig_mem.add_hline(y=28900, line_color='#f87171', line_dash='dash', annotation_text='Node RAM limit 28.9 GB', annotation_font_color='#f87171') fig_mem.add_hline(y=17180, line_color='#fbbf24', line_dash='dash', annotation_text='30q = 17.2 GB (measured)', annotation_font_color='#fbbf24') fig_mem.add_annotation( x=40, y=4, text="40q = 17.6 TB
(impossible SV)", showarrow=True, arrowhead=2, arrowcolor='#f87171', font=dict(color='#f87171', size=10, family='JetBrains Mono'), ax=-65, ay=-35, bgcolor='rgba(248,113,113,0.12)', ) fig_mem.update_layout( **PD, height=400, xaxis=dict(title='Number of qubits', range=[10, 43], gridcolor='#1a2d4a'), yaxis=dict(title='Memory (MB, log)', type='log', gridcolor='#1a2d4a'), title=dict(text='Memory scaling — 30q = node limit · 40q = 17.6 TB', font=dict(size=12)), ) st.plotly_chart(fig_mem, use_container_width=True) # Benchmark table st.markdown("#### Complete Benchmark Data — 12q to 40q (+ Extrapolated)") if scl_all: tbl = [] for r, src in zip(scl_all, scl_srcs): mem_mb = float(r.get('state_vec_mb', 0)) tbl.append({ 'Qubits': f"{r['n_qubits']}q", 'Time/eval': f"{r['mean_time']:.3f}s" if r['mean_time'] < 3600 else f"{r['mean_time']/3600:.1f}h", 'State-vector RAM': f"{mem_mb/1024:.2f} GB" if mem_mb > 1024 else f"{mem_mb:.1f} MB", 'Source': src, 'Hardware': 'Fujitsu A64FX MPI' if src == 'MPI measured' else ('Extrapolated' if src == 'Extrapolated' else 'A64FX single-node'), 'VQE Energy': f"{float(r.get('energy', 0)):.4f}" if r.get('energy') else 'N/A', }) tbl.append({ 'Qubits': '40q', 'Time/eval': f"{t40h:.0f}h ({t_40q:,.0f}s)", 'State-vector RAM': '17,592 GB (17.6 TB)', 'Source': f'Extrapolated R²={r_squared:.4f}', 'Hardware': 'Impossible — requires ~606 × A64FX nodes', 'VQE Energy': f'{vqe_e0_40:.4f} (encoded)', }) st.dataframe(pd.DataFrame(tbl), hide_index=True, use_container_width=True) # VQE convergence at 12q if hist_12: st.markdown("---") st.markdown("#### VQE Convergence at 12q — Benchmark Hamiltonian") fig_12 = go.Figure(go.Scatter( x=list(range(len(hist_12))), y=list(hist_12), mode='lines', line=dict(color='#38bdf8', width=2), fill='tozeroy', fillcolor='rgba(56,189,248,0.06)', )) fig_12.add_hline(y=float(hist_12[-1]), line_color='#34d399', line_dash='dash', annotation_text=f'E_final={float(hist_12[-1]):.4f}', annotation_font_color='#34d399') fig_12.update_layout( **PD, height=240, xaxis=dict(title='Iteration', gridcolor='#1a2d4a'), yaxis=dict(title='Energy', gridcolor='#1a2d4a'), title=dict(text='12q VQE convergence — supply-chain benchmark Hamiltonian', font=dict(size=12)), ) st.plotly_chart(fig_12, use_container_width=True) # ══════════════════════════════════════════════════════════════ # PAGE 6 — QARP FEEDBACK # ══════════════════════════════════════════════════════════════ elif page == "📋 QARP Feedback": st.markdown('
Fujitsu QARP Usability Feedback
', unsafe_allow_html=True) st.markdown("""
QR-SPPS Project · Fujitsu Quantum Simulator Challenge 2025-26 · Comprehensive feedback on QARP API, algorithms, and platform experience
""", unsafe_allow_html=True) # Overall score banner st.markdown("""
4.1
Overall Score
★★★★☆
Fujitsu QARP: Production-Ready Algorithms · ARM Compatibility Needs Attention
QARP's algorithm implementations (VQE, ADAPT-VQE gradient screening, DOS-QPE) are scientifically sound and enabled genuinely novel supply-chain quantum simulation. The primary obstacle is QulacsEngine incompatibility with A64FX ARM — once resolved via TketEngine(AerBackend), all algorithms performed excellently. The OpenFermion + QARP Hamiltonian pipeline mapped naturally to our Ising supply-chain model.
""", unsafe_allow_html=True) # Ratings grid st.markdown("### Component Ratings") ratings = [ ("QARP Installation & Setup", 5, "#34d399", "setup_env.sh worked cleanly on both login and compute nodes. pyenv + venv workflow is clean and reproducible. Requirements.txt complete."), ("QARP Documentation", 4, "#34d399", "mwe_vqe.py, mwe_adapt_vqe_vqd.py, mwe_dosqpe_algo.py are excellent. Missing: ARM-specific warnings and Jupyter/MPI incompatibility note."), ("VQE Algorithm", 5, "#34d399", "Clean API, COBYLA converged reliably on 30q supply-chain Hamiltonians (depth=3, 120 params, 5 restarts). E₀ = −44.6931 matches NB1 exact with zero error."), ("ADAPT-VQE Gradient Screening", 5, "#34d399", "Highly effective for policy ranking — ranked 6 interventions without full re-optimisation. Exactly the quantum efficiency gain needed for real-world policy applications."), ("DOS-QPE Survival Amplitude", 4, "#34d399", "Correct spectral reconstruction from mwe_dosqpe_algo.py pattern. 64 Trotter steps produced clean DOS. FFT + Hanning window pipeline worked directly."), ("OpenFermion Integration", 5, "#34d399", "QubitOperator → QARP Hamiltonian pipeline worked cleanly. ZZ + X Pauli encoding mapped naturally to Ising supply-chain structure with 57 supply edges."), ("TketEngine + AerBackend", 4, "#34d399", "Reliable QulacsEngine replacement. Worked consistently across all 4 notebooks once QulacsEngine segfault was diagnosed. Slightly slower than native Qulacs."), ("MPI / Distributed Support", 3, "#fbbf24", "mpi4py works correctly in sbatch scripts. Cannot be imported in Jupyter on compute nodes (OMPI not built with SLURM PMI). Needs better documentation."), ("QulacsEngine on A64FX ARM", 2, "#f87171", "Segfaults on ARM A64FX compute nodes — SIGSEGV at C extension level, uncatchable by Python try/except. Worked on x86 login node only. Required 3h to diagnose."), ("Error Messages & Diagnostics", 3, "#fbbf24", "Algorithm-level errors are clear. C-extension segfaults give no Python traceback. Recommending: QARP_DISABLE_MPI flag + ARM binary distribution."), ] col_a, col_b = st.columns(2) for i, (aspect, rating, color, comment) in enumerate(ratings): col = col_a if i % 2 == 0 else col_b with col: stars = "★" * rating + "☆" * (5 - rating) bar_w = int(rating / 5 * 100) st.markdown(f"""
{aspect} {stars}  {rating}/5
{comment}
""", unsafe_allow_html=True) st.markdown("---") # Issues & positives issue_col, pos_col = st.columns(2) with issue_col: st.markdown("### 🔴 Issues Encountered") issues = [ ("#f87171", "CRITICAL", "QulacsEngine Segfault on A64FX", "QulacsEngine (.pyc) segfaults on ARM A64FX compute nodes — SIGSEGV at C extension level. Root cause: MPI_Init inside constructor; OMPI not built with SLURM PMIx.", "Replaced with direct qulacs Observable API + TketEngine(AerBackend). Took ~3h to diagnose.", "Distribute as .py source or provide ARM binary. Add QARP_DISABLE_MPI=1 to suppress C-level MPI init."), ("#f87171", "CRITICAL", "MPI Crashes Jupyter Kernel", "Importing mpi4py inside Jupyter on compute node causes immediate kernel crash: OPAL ERROR — OMPI not built with SLURM PMI support.", "All MPI code moved to sbatch scripts. Jupyter used for algorithm development only.", "Document this limitation prominently. Provide QARP_NO_MPI flag at C level."), ("#fbbf24", "HIGH", "Login vs Compute Node Architecture", "Login node is x86; compute nodes are ARM A64FX. Code that works on login node fails on compute nodes. Not documented.", "Learned through trial and error. All quantum code moved to compute nodes.", "Add prominent README warning: all quantum code must run on compute nodes only."), ("#fbbf24", "MEDIUM", "Interactive Partition 30-min Time Limit", "Insufficient for 28q+ benchmarks. 29q = 595s, 30q = 1192s per eval requires extended allocation.", "Used --time=12:00:00 for benchmark jobs.", "Provide 2–4h partition or document qubit limits per partition."), ] for color, sev, title, detail, fix, rec in issues: st.markdown(f"""
{sev} {title}
{detail}
✓ Workaround: {fix}
→ Recommendation: {rec}
""", unsafe_allow_html=True) with pos_col: st.markdown("### 🟢 What Worked Well") positives = [ ("QARP VQE API", f"Clean interface, COBYLA converged reliably on 30q supply-chain Hamiltonians. VQE reached E₀ = {vqe_e0_40:.4f} (40q scaled) with zero error vs exact diagonalisation."), ("ADAPT-VQE Gradient Screening", "Ranked 6 policy interventions (Rate hike, Supplier subsidy, Stockpile release, Trade diversion, Combined optimal) without full re-optimisation — exactly the quantum efficiency needed."), ("DOS-QPE Spectral Reconstruction", "64-step Trotter survival amplitude + Hanning FFT produced clean density of states. Pattern from mwe_dosqpe_algo.py was directly applicable to supply-chain Hamiltonian."), ("TketEngine + AerBackend Fallback", "Reliable QulacsEngine replacement. Worked consistently across all 4 notebooks once QulacsEngine was bypassed. Essential for A64FX ARM compatibility."), ("OpenFermion QubitOperator Integration", "ZZ + X Pauli encoding mapped naturally to Ising supply-chain structure. 57-edge supply network → Hamiltonian in < 10 lines of QARP code."), ("Example Scripts Quality", "mwe_vqe.py, mwe_adapt_vqe_vqd.py, mwe_dosqpe_algo.py: clear, well-commented, directly adaptable. Best part of the documentation package."), ("MPI Scaling Performance", "qulacs with MPI enabled scales correctly: 24q→30q measured on Fujitsu A64FX with R²=0.9948 exponential fit. 30q = 17.2 GB (measured) confirms performance claims."), ] for title, detail in positives: st.markdown(f"""
{title}
{detail}
""", unsafe_allow_html=True) st.markdown("### 📋 Priority Recommendations") recs = [ ("#f87171", "P1", "Fix QulacsEngine ARM A64FX", "Distribute as .py source or ARM binary. Showstopper for the competition platform."), ("#f87171", "P1", "Document Jupyter + MPI limitation", "Add clear note: mpi4py cannot be used in Jupyter on this cluster."), ("#fbbf24", "P2", "Architecture-specific setup guide", "Warn: login=x86, compute=ARM. All quantum code must run on compute nodes."), ("#fbbf24", "P2", "Extend Interactive partition time", "2–4h minimum for 28q+ workloads (currently 30min)."), ("#38bdf8", "P3", "QARP health-check script", "Verify all engines on current architecture before users spend hours debugging."), ("#38bdf8", "P3", "Progress callbacks for DOS-QPE", "Long Trotter evolutions need progress indicators."), ] for col, pri, title, detail in recs: st.markdown(f"""
{pri} {title}
{detail}
""", unsafe_allow_html=True) # Conclusion st.markdown("---") st.markdown(f"""
⚛ Conclusion
Fujitsu QARP is a scientifically rigorous quantum algorithm library. VQE, ADAPT-VQE gradient screening, and DOS-QPE enabled genuine novel applications in supply-chain quantum risk simulation that would not be possible with classical methods. The ADAPT-VQE policy ranking was the standout feature — ranking 6 interventions by gradient without full re-optimisation is exactly the kind of quantum speedup that justifies real-world deployment. The primary obstacle — QulacsEngine incompatibility with A64FX ARM — is a single issue that, once resolved, would make QARP the definitive quantum algorithm library for the Fujitsu platform. The TketEngine fallback proved it is an engineering fix, not a fundamental limitation.
✓ Algorithm quality: 5/5
✓ API design: 4.5/5
⚠ ARM compatibility: 2/5 (fixable)
Overall: 4.1/5
""", unsafe_allow_html=True) # ── Footer ───────────────────────────────────────────────────── st.markdown("""
QR-SPPS  ·  FUJITSU QUANTUM SIMULATOR CHALLENGE 2025-26  ·  VQE  ·  ADAPT-VQE  ·  DOS-QPE
40q encoded · 30q executed (17.2 GB MPI measured) · 40q extrapolated (17.6 TB, 1308h/eval)
""", unsafe_allow_html=True)