# grafic.py — Ghid local pentru IBM Quantum Composer (CHSH)
# - Creează 8 circuite: 4 entangled (|Φ+⟩) + 4 separabile (|00⟩)
# - Salvează PNG + OpenQASM2 pentru fiecare circuit
# - Face o grilă 2×4 din PNG-uri + o legendă textuală

# === 0) Backend Matplotlib fără GUI (robust pe Windows) ===
import matplotlib
matplotlib.use("Agg")  # evita FigureCanvasTkAgg; randare off-screen

# === 1) Importuri generale ===
import math
from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt

from qiskit import QuantumCircuit
from qiskit.qasm2 import dumps as qasm2_dumps  # Export corect la QASM2 (Qiskit ≥ 1.0)

OUTDIR = Path("chsh_outputs")
OUTDIR.mkdir(exist_ok=True)

# === 2) Utilitare pentru vizualizare și export ===
def save_png(circ: QuantumCircuit, stem: str):
    """
    Salvează un PNG al circuitului (folosind desenatorul 'mpl').
    Recomandat în afara Jupyter: draw(output="mpl") + savefig().
    """
    fig = circ.draw(output="mpl", fold=-1)  # returnează matplotlib.Figure
    fig.savefig(OUTDIR / f"{stem}.png", dpi=180, bbox_inches="tight")
    plt.close(fig)

def save_qasm2(circ: QuantumCircuit, stem: str):
    """
    Exportă circuitul în OpenQASM 2 (Composer suportă QASM 2.0).
    """
    qasm_text = qasm2_dumps(circ)  # string QASM2
    (OUTDIR / f"{stem}.qasm").write_text(qasm_text, encoding="utf-8")

def save_legend_png(outpath: Path):
    """
    Creează o legendă textuală cu pașii de tras în Composer.
    """
    steps = [
        "ENTANGLED (|Φ⁺⟩): H(q0) → CX(q0→q1) → RY(−2·Aθ) pe q0 → RY(−2·Bθ) pe q1 → Measure Z",
        "SEPARABLE (|00⟩): RY(−2·Aθ) pe q0 → RY(−2·Bθ) pe q1 → Measure Z",
        "Seturi CHSH: (A0,B0), (A0,B1), (A1,B0), (A1,B1)",
        "A0=0, A1=π/4; B0=π/8, B1=−π/8 (radiani); în Composer scrie: pi/8, -pi/8, pi/4",
    ]
    fig = plt.figure(figsize=(8, 4.8))
    y = 0.95
    plt.text(0.02, y, "Composer cheat-sheet (CHSH)", fontsize=12, va="top"); y -= 0.08
    for s in steps:
        plt.text(0.02, y, "• " + s, fontsize=10, va="top"); y -= 0.08
    plt.axis("off")
    fig.savefig(outpath, dpi=180, bbox_inches="tight")
    plt.close(fig)

def save_composer_grid_from_pngs(outdir: Path):
    """
    Compune o grilă 2×4 din PNG-urile individuale salvate mai jos.
    Evităm accesul la canvas; citim direct imaginile.
    """
    items = [
        ("entangled_ab.png",   "ENTANGLED  A0=0,     B0=π/8"),
        ("entangled_abp.png",  "ENTANGLED  A0=0,     B1=−π/8"),
        ("entangled_apb.png",  "ENTANGLED  A1=π/4,   B0=π/8"),
        ("entangled_apbp.png", "ENTANGLED  A1=π/4,   B1=−π/8"),
        ("separable_ab.png",   "SEPARABLE  A0=0,     B0=π/8"),
        ("separable_abp.png",  "SEPARABLE  A0=0,     B1=−π/8"),
        ("separable_apb.png",  "SEPARABLE  A1=π/4,   B0=π/8"),
        ("separable_apbp.png", "SEPARABLE  A1=π/4,   B1=−π/8"),
    ]
    fig, axes = plt.subplots(2, 4, figsize=(16, 6))
    axes = axes.flatten()
    for ax, (fname, title) in zip(axes, items):
        img = plt.imread(outdir / fname)
        ax.imshow(img)
        ax.axis("off")
        ax.set_title(title, fontsize=10)
    fig.suptitle("Composer guide — ENTANGLED: H→CX→RY(−2θ)→Meas | SEPARABLE: RY(−2θ)→Meas", fontsize=12)
    fig.tight_layout()
    fig.savefig(outdir / "composer_guide.png", dpi=180, bbox_inches="tight")
    plt.close(fig)

# === 3) Construcția circuitelor CHSH ===
def rot_measure(qc: QuantumCircuit, q: int, theta: float):
    """
    Măsurare într-o bază rotită (plan X–Z) aplicând RY(−2·θ), apoi măsurare în Z.
    """
    qc.ry(-2.0 * theta, q)

def build_entangled(a: float, b: float, name: str) -> QuantumCircuit:
    qc = QuantumCircuit(2, 2, name=name)
    # |Φ+> = (|00> + |11>)/√2
    qc.h(0); qc.cx(0, 1)
    rot_measure(qc, 0, a)  # Alice
    rot_measure(qc, 1, b)  # Bob
    qc.measure([0, 1], [0, 1])
    return qc

def build_separable(a: float, b: float, name: str) -> QuantumCircuit:
    qc = QuantumCircuit(2, 2, name=name)  # |00>
    rot_measure(qc, 0, a)
    rot_measure(qc, 1, b)
    qc.measure([0, 1], [0, 1])
    return qc

# Seturi CHSH (max. violare): A0=0, A1=π/4; B0=π/8, B1=−π/8
A0, A1, B0, B1 = 0.0, math.pi/4.0, math.pi/8.0, -math.pi/8.0

# 4 entangled
circ_E_ab    = build_entangled(A0, B0, "E_ab")
circ_E_abp   = build_entangled(A0, B1, "E_abp")
circ_E_apb   = build_entangled(A1, B0, "E_apb")
circ_E_apbp  = build_entangled(A1, B1, "E_apbp")
# 4 separabile
circ_S_ab    = build_separable(A0, B0, "S_ab")
circ_S_abp   = build_separable(A0, B1, "S_abp")
circ_S_apb   = build_separable(A1, B0, "S_apb")
circ_S_apbp  = build_separable(A1, B1, "S_apbp")

# === 4) Salvare PNG + QASM2 pentru Composer ===
for stem, c in [
    ("entangled_ab",   circ_E_ab),   ("entangled_abp",  circ_E_abp),
    ("entangled_apb",  circ_E_apb),  ("entangled_apbp", circ_E_apbp),
    ("separable_ab",   circ_S_ab),   ("separable_abp",  circ_S_abp),
    ("separable_apb",  circ_S_apb),  ("separable_apbp", circ_S_apbp),
]:
    save_png(c, stem)
    save_qasm2(c, stem)

# === 5) Grila 2×4 și legenda ===
save_composer_grid_from_pngs(OUTDIR)
save_legend_png(OUTDIR / "composer_legend.png")

print(f"Gata. Verificați: {OUTDIR.resolve()} →")
print(" - PNG + .qasm (QASM2) pentru fiecare circuit")
print(" - composer_guide.png (grilă 2×4)")
print(" - composer_legend.png (pașii de trasat în Composer)")
