#!/usr/bin/env python3
"""
Capitoli 5 e 7: tabelle tratte dai dati del Quantum Advantage Tracker.

Fonte: istantanea dei file JSON del repository
quantum-advantage-tracker/quantum-advantage-tracker.github.io (licenza
Apache 2.0) in figure/dati/tracker, commit dichiarato in
figure/dati/TRACKER-SNAPSHOT.txt. È, con l'istantanea stessa, l'unica
eccezione del volume ai dati costruiti: i valori sono copiati, non calcolati.

Produce:
    c05_tabella_ole.txt       contributi accettati sulle istanze OLE (Algorithmiq)
    c05_ole.dat               valori per istanza e metodo, per il grafico a punti
    c07_tabella_istanze.txt   istanze per percorso e categoria
    c07_tabella_conteggi.txt  contributi accettati per percorso, quantistici e classici
"""

import json
import os

from comune import HERE, scrivi_dat, scrivi_txt, it, it_sci

BASE = os.path.join(HERE, "dati", "tracker")
PERCORSI = [
    ("observable-estimations", "circuit-models.json", "observable estimations"),
    ("variational-problems", "hamiltonians.json", "variational problems"),
    ("classically-verifiable-problems", "circuit-models.json", "classically verifiable problems"),
]
CATEGORIE = {
    "Active candidates": "active candidate",
    "Superseded candidates": "superseded candidate",
    "Baseline benchmarks": "baseline benchmark",
}


def carica(percorso, nome):
    with open(os.path.join(BASE, percorso, nome)) as f:
        return json.load(f)


def quantistico(s):
    return "runtimeQuantum" in s


def numero_issue(s):
    return "\\#" + s["url"].rstrip("/").split("/")[-1]


# ------------------------------------------------ OLE
sub = carica("observable-estimations", "submissions.json")
ole = [s for s in sub if s["circuit"].startswith("operator_loschmidt_echo")]
ordine = ["operator_loschmidt_echo_49x648", "operator_loschmidt_echo_49x1296",
          "operator_loschmidt_echo_70x1872", "operator_loschmidt_echo_56x1488"]
ole.sort(key=lambda s: (ordine.index(s["circuit"]), not quantistico(s), s["createdAt"]))
righe = []
for s in ole:
    ist = s["circuit"].replace("operator_loschmidt_echo_", "").replace("x", "$\\times$")
    tipo = "quantistico" if quantistico(s) else "classico"
    if quantistico(s):
        risorse = f"{s.get('computeResourcesQuantum', '')}, {it(s['runtimeQuantum'], 0)} s".replace("_", "\\_")
    else:
        risorse = f"{it(s.get('runtimeClassical', 0), 0)} s"
    metodo = (s["method"].replace("Belief Propagation TN", "BP-TN")
              .replace("no rescaling", "no rescaling")
              .replace("rescaled by delta = 0.0", "rescaled ($\\delta = 0$)")
              .replace("rescaled", "rescaled")
              .replace("Global rescaling", "global rescaling")
              .replace("Single-path Monte Carlo", "single-path Monte Carlo")
              .replace("_", "\\_"))
    righe.append([ist, tipo, metodo, it(s["observableValue"], 3), risorse, numero_issue(s)])
    print(s["circuit"], tipo, s["observableValue"], s["method"])
scrivi_txt("c05_tabella_ole.txt",
           ["istanza", "tipo", "metodo", "valore", "risorse e tempo", "issue"], righe,
           "dati del Quantum Advantage Tracker, istantanea in figure/dati/tracker")

# dati per il grafico: indice istanza (1, 2, 3), valore, colonne per tipo di metodo
punti = []
for s in ole:
    k = ordine.index(s["circuit"]) + 1
    m = s["method"].lower()
    gruppo = ("quantistico" if quantistico(s) else
              "bptn_riscalato" if "rescaled" in m and "no rescaling" not in m else
              "bptn" if "belief" in m or "bp" in m else "montecarlo")
    punti.append([k, s["observableValue"], gruppo])
scrivi_dat("c05_ole.dat", "istanza valore gruppo  (1 = 49x648, 2 = 49x1296, 3 = 70x1872)",
           [[p[0], p[1], p[2]] for p in punti])

# ------------------------------------------------ istanze per percorso
righe = []
conteggi = []
for percorso, file_ist, nome in PERCORSI:
    ist = carica(percorso, file_ist)
    sub = carica(percorso, "submissions.json")
    for modello, d in ist.items():
        istanze = d["instances"]
        if modello == "n2_ccpvdz":   # nove geometrie dello stesso problema: una riga sola
            istanze = istanze[:1]
        for i in istanze:
            dim = (f"{i['qubits']} qubit, {it(i['gates'], 0)} gate" if "qubits" in i
                   else f"spazio di Hilbert ${it_sci(float(i['hilbert_space_size']), 2)}$")
            nome_ist = ("9 geometrie (0,80--3,00 \\AA)" if modello == "n2_ccpvdz"
                        else i["id"].replace(modello + "_", "").replace("_", "\\_"))
            righe.append([nome, modello.replace("_", "\\_"), nome_ist,
                          dim, CATEGORIE.get(i.get("category", ""), i.get("category", ""))])
    nq = sum(1 for s in sub if quantistico(s))
    conteggi.append([nome, str(len(sub)), str(nq), str(len(sub) - nq)])
scrivi_txt("c07_tabella_istanze.txt", ["percorso", "modello", "istanza", "dimensione", "categoria"], righe,
           "dati del Quantum Advantage Tracker, istantanea in figure/dati/tracker")
scrivi_txt("c07_tabella_conteggi.txt", ["percorso", "submission accettate", "quantistiche", "classiche"], conteggi,
           "submission unite in submissions.json; le issue ancora aperte non sono contate")
for c in conteggi:
    print(c)
