""" QAOA Pedagogical Tool — Main Entry Point ========================================= Run with: streamlit run app.py Navigation is driven entirely by st.session_state["page"]. The landing page renders three clickable module cards. Each module page has a "← Back to Home" button. """ import streamlit as st # ── Page config (must be first Streamlit call) ─────────────────────────────── st.set_page_config( page_title="QAOA Pedagogical Tool", page_icon="⚛️", layout="wide", initial_sidebar_state="collapsed", ) # ── Global CSS ──────────────────────────────────────────────────────────────── st.markdown(""" """, unsafe_allow_html=True) st.markdown(""" """, unsafe_allow_html=True) # ── Session state initialisation ────────────────────────────────────────────── if "page" not in st.session_state: st.session_state["page"] = "home" # ═════════════════════════════════════════════════════════════════════════════ # LANDING PAGE # ═════════════════════════════════════════════════════════════════════════════ def render_home(): # ── Header ─────────────────────────────────────────────────────────────── st.markdown( '

' 'QAOA Pedagogical Tool

', unsafe_allow_html=True, ) st.markdown( '

' 'An interactive step-by-step guide to the ' 'Quantum Approximate Optimization Algorithm

', unsafe_allow_html=True, ) # ── Quick-reference math ────────────────────────────────────────────────── st.markdown("---") col_a, col_b, col_c = st.columns(3) with col_a: with st.container(border=True, height=120): st.markdown("**QUBO → Hamiltonian**") st.latex(r"x_i \to \frac{I - Z_i}{2}") with col_b: with st.container(border=True, height=120): st.markdown("**Cost Layer**") st.latex(r"U_C(\gamma) = e^{-i\gamma H_C}") with col_c: with st.container(border=True, height=120): st.markdown("**Mixer Layer**") st.latex(r"U_B(\beta) = e^{-i\beta \sum X_i}") # ── Module cards ───────────────────────────────────────────────────────── st.markdown( '

Choose a Module

', unsafe_allow_html=True, ) col1, col2, col3 = st.columns(3) with col1: st.markdown("""
⚛️
Standard QAOA
3 Qubits · Unconstrained
Start here. Learn QUBO formulation, Hamiltonian mapping, and the Phase–Probability Disconnect from first principles.

Problem: Minimize C(x) = x₁ + x₂ − x₂x₃
""", unsafe_allow_html=True) if st.button("Open →", key="go_standard", use_container_width=False): st.session_state["page"] = "standard" st.rerun() with col2: st.markdown("""
🔒
Equality Constraint
3 Qubits · Penalty Method
Learn how to encode equality constraints as quadratic penalty terms, and see why this creates a fully-connected K₃ cost circuit.

Problem: Minimize C(x) = x₁ + x₂ − x₂x₃
Constraint: x₁ + x₂ + x₃ = 1
""", unsafe_allow_html=True) if st.button("Open →", key="go_equality", use_container_width=False): st.session_state["page"] = "equality" st.rerun() with col3: st.markdown("""
📐
Inequality Constraint
4 Qubits · Slack Variable
Advanced module. Introduce a binary slack qubit to convert an inequality into an equality, building a K₄ fully-connected circuit.

Problem: Minimize C(x) = x₁ + x₂ − x₂x₃
Constraint: x₁ + x₂ + x₃ ≥ 2
""", unsafe_allow_html=True) if st.button("Open →", key="go_inequality", use_container_width=False): st.session_state["page"] = "inequality" st.rerun() # ── How to use ─────────────────────────────────────────────────────────── st.markdown("---") with st.expander("How to use this tool"): st.markdown(""" Each module walks you through **six pedagogical steps**: 1. **Problem Formulation** — binary optimization problem + truth table 2. **QUBO Matrix** — encode the cost as a matrix 3. **Hamiltonian Mapping** — translate to quantum spin operators 4. **Circuit Construction** — see how each Hamiltonian term becomes a gate; observe the **Phase–Probability Disconnect** using sv_disc visualizations 5. **Interactive Simulation** — adjust γ and β sliders to explore the energy landscape 6. **COBYLA Optimization + Replay** — run the variational loop, then scrub through the optimization history iteration by iteration **Phase–Probability Disconnect** (Step 4): Each disc represents one basis state. The *radius* encodes the probability amplitude; the *angle* of the pointer encodes the quantum phase. After the Cost Layer, all radii are equal (probabilities unchanged) but angles differ. After the Mixer Layer, radii change — this is where interference converts phase into probability. """) # ── Footer ──────────────────────────────────────────────────────────────── st.markdown( '

' 'Built with Qiskit · Streamlit · Plotly · sv_disc  |  ' 'IEEE QSEEC 2026 Submission

', unsafe_allow_html=True, ) # ═════════════════════════════════════════════════════════════════════════════ # ROUTER # ═════════════════════════════════════════════════════════════════════════════ def main(): page = st.session_state.get("page", "home") if page == "home": render_home() elif page == "standard": from pages.standard import render render() elif page == "equality": from pages.equality import render render() elif page == "inequality": from pages.inequality import render render() else: st.session_state["page"] = "home" st.rerun() if __name__ == "__main__": main()