from collections import deque
import matplotlib.pyplot as plt
import numpy as np
import json

from pyqcs import State, H, X, S, CZ
from pyqcs.graph.state import GraphState
from pyqcs.util.random_circuits import random_circuit

from measure_circuit import execution_statistics

def S_with_extra_arg(act, i):
    return S(act)

def test_scaling_qbits(state_factory
                    , nstart
                    , nstop
                    , ngates_per_qbit
                    , ncircuits
                    , **kwargs):
    results = deque()
    for qbits in range(nstart, nstop):
        circuits = [random_circuit(qbits, ngates_per_qbit * qbits, X, H, S_with_extra_arg, CZ)
                        for _ in range(ncircuits)]
        state = state_factory(qbits)

        print("running test with", qbits, "qbits")
        N, avg, std_dev = execution_statistics(circuits, state, scale=qbits, **kwargs)

        results.append([qbits, N, avg, std_dev])
    return np.array(results, dtype=np.double)

if __name__ == "__main__":
    nstart = 4
    nstop = 16
    ncircuits = 50
    ngates_per_qbit = 100
    seed = 0xdeadbeef

    np.random.seed(seed)
    results_naive = test_scaling_qbits(State.new_zero_state
                                    , nstart
                                    , nstop
                                    , ngates_per_qbit
                                    , ncircuits
                                    , repeat=10)
    np.random.seed(seed)
    results_graph = test_scaling_qbits(GraphState.new_zero_state
                                    , nstart
                                    , nstop
                                    , ngates_per_qbit
                                    , ncircuits
                                    , repeat=10)

    np.savetxt("qbit_scaling_naive.csv", results_naive)
    print("saved naive results to qbit_scaling_naive.csv")
    np.savetxt("qbit_scaling_graph.csv", results_graph)
    print("saved graph results to qbit_scaling_graph.csv")

    meta = {"nstart": nstart
            , "nstop": nstop
            , "ncircuits": ncircuits
            , "ngates_per_qbit": ngates_per_qbit
            , "seed": seed}

    with open("qbit_scaling_meta.json", "w") as fout:
        json.dump(meta, fout)
    print("saved meta data to qbit_scaling_meta.json")

