""" Council AI — Theorem Explorer ------------------------------ Interactive companion to "Council AI: Toward Deliberative Artificial Intelligence" (Michael Jidael, Udochukwu Nwokoma, Benjamin Ogbonna, et al., Nexenda, 2026). Implements exactly two things, both taken directly from the paper's proofs: Theorem 1 (Deliberation Convergence): ||H(t) - H*||_F <= gamma^t * ||H(0) - H*||_F Theorem 2 (Multi-Expert Safety Bound): P(catastrophic error) <= p * rho^(k-1) if p <= rho P(catastrophic error) <= p^k if p > rho No proprietary architecture names, expert-cluster names, or product names appear anywhere in this app or its outputs. Consistent with the naming constraints on Paper 1. """ import spaces # must come first, before numpy/matplotlib/gradio @spaces.GPU(duration=1) def _zerogpu_keepalive(): """No-op. ZeroGPU refuses to start a Space with no @spaces.GPU function.""" return None import numpy as np import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt from matplotlib.ticker import MaxNLocator import gradio as gr # Links PAPER_URL = "#" CODE_URL = "#" WEBSITE_URL = "https://nexendahq.com/" # Plot palette. Theme-neutral on purpose: transparent background, mid-grey # text/grid that reads on both the light and dark card, and the same # accent colours in both themes. The light/dark switch is therefore pure # client-side CSS (no server round trip, no theme state). ORANGE, GREEN, PINK = "#E8651A", "#5E9E4E", "#D6456B" INK = "#8F8D85" def style_axes(fig, ax): fig.patch.set_facecolor("none") ax.set_facecolor("none") for spine in ax.spines.values(): spine.set_color(INK) spine.set_alpha(0.35) spine.set_linewidth(0.8) ax.tick_params(colors=INK, labelsize=8.5, length=0, pad=8) ax.xaxis.label.set_color(INK) ax.yaxis.label.set_color(INK) ax.xaxis.label.set_size(8.5) ax.yaxis.label.set_size(8.5) ax.grid(color=INK, alpha=0.3, linewidth=0.7, linestyle=(0, (2, 3))) def legend_html(items): """items: (label, colour, dashed?) -> plot header with title + legend.""" keys = "".join( f'{label}' for label, c, dashed in items ) return f'
{ICON_CHART}Plot
{keys}
' def stats_html(pairs): return '
' + "".join(f"

{k}: {v}

" for k, v in pairs) + "
" # Theorem 1 — Deliberation Convergence def theorem1(gamma: float, rounds: int, d0: float, tau: float): t = np.arange(0, rounds + 1) dist = d0 * (gamma ** t) agreement = np.clip(1 - dist / d0, 0, 1) reached = np.argmax(agreement >= tau) if np.any(agreement >= tau) else None consensus_round = int(reached) if reached is not None and agreement[reached] >= tau else None fig, ax = plt.subplots(figsize=(8.6, 4.6), dpi=160) style_axes(fig, ax) ax.axhline(tau, color=PINK, linestyle=(0, (2, 2)), linewidth=1.4) ax.plot(t, dist / d0, color=ORANGE, linewidth=1.8) ax.plot(t, agreement, color=GREEN, linewidth=1.8) ax.set_xlabel("Deliberation round t", labelpad=12) ax.set_ylabel("Normalized value", labelpad=12) ax.set_ylim(-0.02, 1.05) fig.tight_layout() plt.close(fig) legend = legend_html([("Threshold τ", PINK, True), ("Disagreement Bound", ORANGE, False), ("Agreement", GREEN, False)]) stats = stats_html([ ("Round consensus reached", f"{consensus_round}/{rounds}" if consensus_round is not None else "not reached"), ("Residual disagreement at round T", f"{dist[-1]:.3g}"), ("Convergence rate", f"γ = {gamma:.2f} · lower γ = faster"), ]) return fig, legend, stats DEFAULTS_T1 = (0.55, 15, 1.2, 0.75) def reset_theorem1(): return (*DEFAULTS_T1, *theorem1(*DEFAULTS_T1)) # Theorem 2 — Multi-Expert Safety Bound def safety_bound(p: float, rho: float, k: int) -> float: if p <= rho: return p * (rho ** (k - 1)) return p ** k def theorem2(p: float, rho: float, n: int, k: int): k = min(k, n) regime = "p ≤ ρ · bound = p·ρ^(k−1)" if p <= rho else "p > ρ · tighter bound = p^k" ks = np.arange(1, n + 1) bounds = np.array([safety_bound(p, rho, kk) for kk in ks]) current_bound = safety_bound(p, rho, k) fig, ax = plt.subplots(figsize=(8.6, 4.6), dpi=160) style_axes(fig, ax) ax.axhline(p, color=PINK, linestyle=(0, (2, 2)), linewidth=1.4) ax.plot(ks, bounds, color=ORANGE, linewidth=1.6, marker="o", markersize=3) ax.scatter([k], [current_bound], color=ORANGE, s=90, zorder=5, edgecolor="white", linewidth=1.5) ax.set_yscale("log") ax.xaxis.set_major_locator(MaxNLocator(integer=True, min_n_ticks=1)) ax.set_xlabel("Experts required for high-confidence agreement (k)", labelpad=12) ax.set_ylabel("P(catastrophic error)", labelpad=12) fig.tight_layout() plt.close(fig) reduction = p / current_bound if current_bound > 0 else float("inf") verdict = "below baseline" if current_bound < p else "no improvement" legend = legend_html([(f"Single-model rate p = {p:.4f}", PINK, True), ("Council bound as k increases", ORANGE, False)]) stats = stats_html([ ("Regime", regime), ("Error rate (P)", f"{p:.4g} baseline"), (f"Council bound at k={k}", f"{current_bound:.4g} {verdict}"), ("Reduction factor", f"{reduction:,.1f}× vs. model"), ]) return fig, legend, stats DEFAULTS_T2 = (0.01, 0.30, 10, 5) def reset_theorem2(): return (*DEFAULTS_T2, *theorem2(*DEFAULTS_T2)) # Static HTML ICON_CHART = ('' '') ICON_MOON = ('' '') ICON_SUN = ('' '') ICON_ARROW = ('') ICON_CHEV = ('') ICON_INFO = ('') ICON_CHEVL = ('') ICON_CHEVR = ('') MOBILE_NAV_HTML = f"""
""" TOPBAR_HTML = f"""
Nexenda Alignment Research
Website {ICON_ARROW}
""" HERO_HTML = f"""
Council AI - Theorem Explorer

Interactive companion to Council AI: Toward Deliberative Artificial Intelligence.
Both panels compute the paper's theorems live.

Read the paper View code {ICON_CHEV}
""" T1_STATEMENT = ('

If the deliberation operator Φ is contractive with constant γ < 1, ' 'the council state sequence converges exponentially to a unique fixed point: ' '‖H(t) − H*‖ ≤ γᵗ ‖H(0) − H*‖.

') T2_STATEMENT = ('

With n experts, individual error rate p, pairwise error correlation ρ, ' 'and k experts required for a high-confidence output: ' 'P(catastrophic error) ≤ p·ρ^(k−1) when p ≤ ρ; ' 'the tighter bound pᵏ applies when p > ρ.

') NOTICE_HTML = f"""
{ICON_INFO}This demo illustrates the mathematics proven in Theorems 1 and 2 of the Council AI paper. It does not run any trained neural model. Parameters are user-selected inputs to formal bounds, not active system telemetry.
""" # Client-side JS (runs once on load): theme init + toggle, and −/+ steppers # on every slider's number box. INIT_JS = """ () => { if (window.__nxInit) return; window.__nxInit = true; const body = document.body; const apply = (m) => { document.documentElement.dataset.theme = m; body.dataset.theme = m; body.classList.toggle('dark', m === 'dark'); // inline styles so the icon swap never depends on CSS specificity or load order document.querySelectorAll('#theme-toggle .i-sun').forEach((el) => { el.style.display = m === 'dark' ? 'block' : 'none'; }); document.querySelectorAll('#theme-toggle .i-moon').forEach((el) => { el.style.display = m === 'dark' ? 'none' : 'block'; }); }; let saved = null; try { saved = localStorage.getItem('nx-theme'); } catch (e) {} apply(saved || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')); document.addEventListener('click', (e) => { if (!e.target.closest('#theme-toggle')) return; const next = body.dataset.theme === 'dark' ? 'light' : 'dark'; apply(next); try { localStorage.setItem('nx-theme', next); } catch (e) {} }); const switchTab = (dir) => { const tabs = Array.from(document.querySelectorAll('[role="tablist"] [role="tab"]')); if (!tabs.length) return; const cur = tabs.findIndex((t) => t.getAttribute('aria-selected') === 'true'); const next = tabs[(cur + dir + tabs.length) % tabs.length]; if (next) next.click(); }; document.addEventListener('click', (e) => { if (e.target.closest('#mobile-tab-prev')) switchTab(-1); if (e.target.closest('#mobile-tab-next')) switchTab(1); }); const decorate = () => { apply(body.dataset.theme); document.querySelectorAll('.dslider').forEach((el) => { const num = el.querySelector('input[type=number]'); if (!num || num.dataset.stepper) return; num.dataset.stepper = '1'; const mk = (sym, dir) => { const b = document.createElement('button'); b.type = 'button'; b.className = 'step-btn'; b.textContent = sym; b.setAttribute('aria-label', dir > 0 ? 'Increase' : 'Decrease'); b.addEventListener('click', (ev) => { ev.preventDefault(); dir > 0 ? num.stepUp() : num.stepDown(); num.dispatchEvent(new Event('input', { bubbles: true })); num.dispatchEvent(new Event('change', { bubbles: true })); }); return b; }; num.parentNode.insertBefore(mk('−', -1), num); num.parentNode.insertBefore(mk('+', 1), num.nextSibling); }); }; new MutationObserver(decorate).observe(document.body, { childList: true, subtree: true }); decorate(); } """ # CSS CUSTOM_CSS = """ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Noto+Serif:ital,wght@0,400;0,500;1,400&display=swap'); :root { --bg:#FEFDF9; --card:#FFFFFF; --border:#E9E7DF; --chip:#F5F3EC; --track:#F0EEE6; --text:#151513; --muted:#5F5E58; --faint:#9A988F; --accent:#E8651A; --btn-bg:#111110; --btn-fg:#FEFDF9; --tab-active:#FFFFFF; } body[data-theme="dark"] { --bg:#121211; --card:#1B1B1A; --border:#2B2B29; --chip:#272725; --track:#262624; --text:#F3F1EA; --muted:#A3A199; --faint:#6D6C66; --btn-bg:#FEFDF9; --btn-fg:#111110; --tab-active:#2B2B29; } body, gradio-app, .gradio-container, .main, .app { background:var(--bg) !important; } .gradio-container { max-width:1440px !important; margin:0 auto !important; padding:0 48px 48px !important; font-family:'Inter',sans-serif !important; color:var(--text); } .gradio-container footer { display:none !important; } .gradio-container .block, .gradio-container .form { background:transparent !important; border:none !important; box-shadow:none !important; padding:0 !important; } /* ---- top bar ---- */ .topbar { display:flex; align-items:center; justify-content:space-between; padding-top:40px; } .wordmark { font-size:15px; font-weight:500; color:var(--text); letter-spacing:-0.005em; } .top-actions { display:flex; align-items:center; gap:10px; } .icon-btn { width:44px; height:44px; border-radius:50%; border:none; background:var(--chip); color:var(--text); display:grid; place-items:center; cursor:pointer; padding:0; flex:none; } .icon-btn .i-sun { display:none; } body[data-theme="dark"] .icon-btn .i-sun { display:block; } body[data-theme="dark"] .icon-btn .i-moon { display:none; } .gradio-container a.pill { display:inline-flex; align-items:center; gap:8px; height:44px; padding:0 28px; border-radius:999px; background:var(--btn-bg); color:var(--btn-fg) !important; text-decoration:none !important; font-size:14.5px; font-weight:500; letter-spacing:0.005em; white-space:nowrap; } .gradio-container a.ghost { display:inline-flex; align-items:center; gap:6px; height:44px; padding:0 16px; color:var(--text) !important; text-decoration:none !important; font-size:14.5px; font-weight:500; } .gradio-container a.pill:hover, .gradio-container a.ghost:hover, .icon-btn:hover { opacity:0.85; } .gradio-container a:focus-visible, .icon-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; } /* ---- hero ---- */ .hero { text-align:center; padding:60px 0 52px; } .hero-title { font-family:'Noto Serif',serif !important; font-weight:500; font-size:clamp(30px,4.6vw,46px); letter-spacing:-0.015em; line-height:1.15; color:var(--text); } .hero-sub { font-family:'Noto Serif',serif !important; font-size:16px; line-height:1.6; color:var(--muted) !important; margin:20px auto 28px; max-width:600px; letter-spacing:0.001em; } .hero-actions { display:flex; justify-content:center; align-items:center; gap:24px; flex-wrap:wrap; row-gap:14px; } /* ---- mobile carousel arrows (tab nav on narrow screens) ---- */ .mobile-tab-nav { display:none; justify-content:flex-end; gap:10px; padding:8px 0 28px; } .mobile-nav-btn { width:36px; height:36px; border-radius:50%; border:1px solid var(--border); background:transparent; color:var(--faint); display:grid; place-items:center; cursor:pointer; padding:0; } .mobile-nav-btn:hover { color:var(--text); border-color:var(--faint); } /* ---- tabs (pill switcher) ---- */ .gradio-container [role="tablist"] { display:inline-flex !important; width:auto !important; gap:4px; padding:4px !important; border:1px solid var(--border) !important; border-radius:999px !important; background:var(--chip) !important; margin-bottom:36px !important; } .gradio-container [role="tablist"]::after, .gradio-container [role="tab"]::after { display:none !important; } .gradio-container [role="tab"] { display:flex !important; align-items:center !important; height:36px !important; box-sizing:border-box !important; border:1px solid transparent !important; border-radius:999px !important; background:transparent !important; color:var(--faint) !important; padding:0 18px !important; font-size:14.5px !important; font-weight:500 !important; letter-spacing:0.001em !important; } .gradio-container [role="tab"][aria-selected="true"] { background:var(--tab-active) !important; color:var(--text) !important; border-color:var(--border) !important; } .gradio-container .tabitem { background:transparent !important; border:none !important; padding:0 !important; } .statement { font-size:15px; line-height:1.65; color:var(--text) !important; margin:0 0 32px; letter-spacing:0.001em; } .statement b { font-weight:600; } /* ---- cards ---- */ .theorem-row { align-items:stretch !important; margin-bottom:32px; } .card { background:var(--card) !important; border:1px solid var(--border) !important; border-radius:16px !important; padding:22px 24px !important; gap:22px !important; box-sizing:border-box !important; } .card:not(.plotcard) { height:100% !important; } .plotcard { display:flex !important; flex-direction:column !important; gap:16px !important; } .plotcard > div:nth-child(2) img, .plotcard > div:nth-child(2) svg { width:100% !important; height:auto !important; display:block !important; } /* ---- sliders ---- */ .dslider { --slider-color:var(--accent); --neutral-200:var(--track); } .dslider .head { display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; } .dslider label span, .dslider [data-testid="block-info"] { font-size:14px !important; font-weight:400 !important; color:var(--muted) !important; background:transparent !important; } .dslider .tab-like-container { display:flex; align-items:center; background:var(--chip) !important; border:none !important; border-radius:8px; padding:4px 6px; } .dslider input[type=number] { width:52px !important; text-align:center; background:transparent !important; border:none !important; box-shadow:none !important; color:var(--text) !important; font-weight:600; font-size:14px; padding:4px !important; -moz-appearance:textfield; } .dslider input[type=number]::-webkit-inner-spin-button, .dslider input[type=number]::-webkit-outer-spin-button { -webkit-appearance:none; margin:0; } .dslider .reset-button { display:none !important; } .step-btn { width:22px; height:22px; border:none; background:transparent; color:var(--faint); cursor:pointer; font-size:15px; line-height:1; border-radius:6px; padding:0; } .step-btn:hover { color:var(--text); background:var(--track); } .dslider .slider_input_container { display:flex; flex-wrap:wrap; align-items:center; } .dslider input[type=range] { order:-1; width:100% !important; height:6px !important; border-radius:999px !important; -webkit-appearance:none; appearance:none; background-color:var(--track) !important; } .dslider input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; width:16px; height:16px; margin-top:-5px; border-radius:50%; background:var(--accent); border:2px solid #fff; box-shadow:0 0 0 1px rgba(0,0,0,0.08); cursor:pointer; } .dslider input[type=range]::-moz-range-thumb { width:12px; height:12px; border-radius:50%; background:var(--accent); border:2px solid #fff; cursor:pointer; } .dslider .min_value, .dslider .max_value { font-size:11px !important; color:var(--faint) !important; margin-top:8px; } .dslider .min_value { margin-right:auto; } .gradio-container button.reset-btn { width:100%; height:48px; border:none !important; border-radius:999px !important; background:var(--chip) !important; color:var(--text) !important; font-size:15px !important; font-weight:400 !important; box-shadow:none !important; } .gradio-container button.reset-btn:hover { background:var(--track) !important; } /* ---- plot card ---- */ .plot-head { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:8px 20px; } .plot-title { display:flex; align-items:center; gap:8px; font-size:15px; font-weight:500; color:var(--text); } .legend { display:flex; flex-wrap:wrap; gap:6px 18px; font-size:12px; color:var(--muted); } .legend i { display:inline-block; width:14px; height:0; border-top:2px solid; margin-right:6px; vertical-align:middle; } .legend i.dash { border-top-style:dashed; } /* ---- stats (now inside the plot card, under the chart) ---- */ .stats { display:flex; flex-direction:row; flex-wrap:wrap; align-items:baseline; gap:6px 26px; flex:none; padding-top:16px; border-top:1px solid var(--border); font-size:12px; color:var(--muted); } .stats p { margin:0; white-space:nowrap; } .stats b { color:var(--text); font-weight:600; } .stats em { color:var(--text); font-style:italic; font-weight:400; } .notice { display:flex; align-items:flex-start; gap:14px; padding:20px 18px; border:1px solid var(--border); border-radius:14px; background:var(--card); font-size:13px; line-height:1.6; color:var(--muted); margin-top:8px; } .notice svg { flex:none; margin-top:2px; } @media (max-width:768px) { .gradio-container { padding:0 16px 32px !important; } .topbar { padding-top:20px; } .wordmark { font-size:14px; } .icon-btn { width:38px; height:38px; } .gradio-container a.pill { padding:0 20px; height:40px; font-size:14px; } .hero { padding:36px 0 8px; } .hero-actions { flex-direction:column; gap:14px; } .gradio-container [role="tablist"] { display:none !important; } .mobile-tab-nav { display:flex !important; } .theorem-row { flex-direction:column !important; } .theorem-row .card { height:auto !important; } .stats { flex-direction:column; gap:8px; } .stats p { white-space:normal; } } """ HEAD_HTML = """ """ % INIT_JS NEXENDA_THEME = gr.themes.Base( primary_hue=gr.themes.colors.orange, neutral_hue=gr.themes.colors.stone, font=gr.themes.GoogleFont("Inter"), ).set(slider_color="#E8651A", color_accent="#E8651A") # UI with gr.Blocks(title="Council AI — Theorem Explorer") as demo: gr.HTML(TOPBAR_HTML) gr.HTML(HERO_HTML) gr.HTML(MOBILE_NAV_HTML) with gr.Tab("Deliberation Convergence"): gr.HTML(T1_STATEMENT) with gr.Row(equal_height=True, elem_classes="theorem-row"): with gr.Column(scale=1, min_width=320, elem_classes="card"): gamma_s = gr.Slider(0.1, 0.9, value=DEFAULTS_T1[0], step=0.01, label="Contraction rate γ", elem_classes="dslider") rounds_s = gr.Slider(4, 30, value=DEFAULTS_T1[1], step=1, label="Deliberation rounds T", elem_classes="dslider") d0_s = gr.Slider(0.2, 2.5, value=DEFAULTS_T1[2], step=0.05, label="Initial disagreement ‖H(0)−H*‖", elem_classes="dslider") tau_s = gr.Slider(0.70, 0.99, value=DEFAULTS_T1[3], step=0.01, label="Consensus threshold τ", elem_classes="dslider") reset1_btn = gr.Button("Reset to defaults", elem_classes="reset-btn") with gr.Column(scale=3, min_width=420, elem_classes="card plotcard"): legend1 = gr.HTML() plot1 = gr.Plot(show_label=False, container=False) stats1 = gr.HTML() t1_inputs = [gamma_s, rounds_s, d0_s, tau_s] t1_outputs = [plot1, legend1, stats1] for ctrl in t1_inputs: ctrl.change(theorem1, inputs=t1_inputs, outputs=t1_outputs) reset1_btn.click(reset_theorem1, inputs=None, outputs=t1_inputs + t1_outputs) demo.load(theorem1, inputs=t1_inputs, outputs=t1_outputs) with gr.Tab("Multi-Expert Safety Bound"): gr.HTML(T2_STATEMENT) with gr.Row(equal_height=True, elem_classes="theorem-row"): with gr.Column(scale=1, min_width=320, elem_classes="card"): p_s = gr.Slider(0.001, 0.15, value=DEFAULTS_T2[0], step=0.001, label="Individual error rate p", elem_classes="dslider") rho_s = gr.Slider(0.0, 1.0, value=DEFAULTS_T2[1], step=0.01, label="Error correlation ρ", elem_classes="dslider") n_s = gr.Slider(2, 15, value=DEFAULTS_T2[2], step=1, label="Total experts n", elem_classes="dslider") k_s = gr.Slider(1, 15, value=DEFAULTS_T2[3], step=1, label="Agreement required k", elem_classes="dslider") reset2_btn = gr.Button("Reset to defaults", elem_classes="reset-btn") with gr.Column(scale=3, min_width=420, elem_classes="card plotcard"): legend2 = gr.HTML() plot2 = gr.Plot(show_label=False, container=False) stats2 = gr.HTML() t2_inputs = [p_s, rho_s, n_s, k_s] t2_outputs = [plot2, legend2, stats2] for ctrl in t2_inputs: ctrl.change(theorem2, inputs=t2_inputs, outputs=t2_outputs) reset2_btn.click(reset_theorem2, inputs=None, outputs=t2_inputs + t2_outputs) demo.load(theorem2, inputs=t2_inputs, outputs=t2_outputs) gr.HTML(NOTICE_HTML) # theme init/toggle + slider steppers (client-side only) demo.load(fn=None, inputs=None, outputs=None, js=INIT_JS) if __name__ == "__main__": demo.launch(css=CUSTOM_CSS, theme=NEXENDA_THEME, head=HEAD_HTML, ssr_mode=False)