import unittest
from qiskit import QuantumRegister
from qiskit import QuantumCircuit, execute
from qiskit.providers.aer import AerSimulator
import numpy as np
import logging
import os

try:
    from . import common
except Exception:
    import common


@unittest.skipUnless(
    os.getenv("SLOW") == "1",
    "Skipping this test (environment variable SLOW must be set to 1)",
)
class TestSpeed(common.TestToasterBase):
    def test_qft25_toaster(self):
        logging.info("======= Starting our function =======")
        qc = self.get_qft25_qc()
        stats = self.execute_and_get_stats(
            self.toaster_backend(),
            # Aer.get_backend("qasm_simulator"),
            qc,
            1,
        )
        print("QFT25 toaster:", stats)
        logging.info("======= Ending our function =======")

    def test_qft25_aer(self):
        logging.info("======= Starting our function =======")
        qc = self.get_qft25_qc()
        qc.save_state()
        stats = self.execute_and_get_stats(
            AerSimulator(method="statevector"), qc, 1,
        )
        print("QFT25 toaster:", stats)
        logging.info("======= Ending our function =======")

    @classmethod
    def execute_and_get_stats(cls, backend, qc, shots):
        job = execute(
            qc,
            optimization_level=0,
            backend=backend,
            shots=shots,
            seed_simulator=1,
        )
        job_result = job.result()
        counts = job_result.get_counts(qc)
        total_counts = 0
        for c in counts:
            total_counts += counts[c]
        ret = dict()
        ret["counts"] = counts
        ret["totalcounts"] = total_counts
        return ret

    @staticmethod
    def get_qft25_qc():
        qc = QuantumCircuit()

        q = QuantumRegister(25, "q")

        qc.add_register(q)

        qc.h(q[24])
        qc.crz(np.pi / 2, q[23], q[24])
        qc.h(q[23])
        qc.crz(np.pi / 4, q[22], q[24])
        qc.crz(np.pi / 2, q[22], q[23])
        qc.h(q[22])
        qc.crz(np.pi / 8, q[21], q[24])
        qc.crz(np.pi / 4, q[21], q[23])
        qc.crz(np.pi / 2, q[21], q[22])
        qc.h(q[21])
        qc.crz(np.pi / 16, q[20], q[24])
        qc.crz(np.pi / 8, q[20], q[23])
        qc.crz(np.pi / 4, q[20], q[22])
        qc.crz(np.pi / 2, q[20], q[21])
        qc.h(q[20])
        qc.crz(np.pi / 32, q[19], q[24])
        qc.crz(np.pi / 16, q[19], q[23])
        qc.crz(np.pi / 8, q[19], q[22])
        qc.crz(np.pi / 4, q[19], q[21])
        qc.crz(np.pi / 2, q[19], q[20])
        qc.h(q[19])
        qc.crz(np.pi / 64, q[18], q[24])
        qc.crz(np.pi / 32, q[18], q[23])
        qc.crz(np.pi / 16, q[18], q[22])
        qc.crz(np.pi / 8, q[18], q[21])
        qc.crz(np.pi / 4, q[18], q[20])
        qc.crz(np.pi / 2, q[18], q[19])
        qc.h(q[18])
        qc.crz(np.pi / 128, q[17], q[24])
        qc.crz(np.pi / 64, q[17], q[23])
        qc.crz(np.pi / 32, q[17], q[22])
        qc.crz(np.pi / 16, q[17], q[21])
        qc.crz(np.pi / 8, q[17], q[20])
        qc.crz(np.pi / 4, q[17], q[19])
        qc.crz(np.pi / 2, q[17], q[18])
        qc.h(q[17])
        qc.crz(np.pi / 256, q[16], q[24])
        qc.crz(np.pi / 128, q[16], q[23])
        qc.crz(np.pi / 64, q[16], q[22])
        qc.crz(np.pi / 32, q[16], q[21])
        qc.crz(np.pi / 16, q[16], q[20])
        qc.crz(np.pi / 8, q[16], q[19])
        qc.crz(np.pi / 4, q[16], q[18])
        qc.crz(np.pi / 2, q[16], q[17])
        qc.h(q[16])
        qc.crz(np.pi / 512, q[15], q[24])
        qc.crz(np.pi / 256, q[15], q[23])
        qc.crz(np.pi / 128, q[15], q[22])
        qc.crz(np.pi / 64, q[15], q[21])
        qc.crz(np.pi / 32, q[15], q[20])
        qc.crz(np.pi / 16, q[15], q[19])
        qc.crz(np.pi / 8, q[15], q[18])
        qc.crz(np.pi / 4, q[15], q[17])
        qc.crz(np.pi / 2, q[15], q[16])
        qc.h(q[15])
        qc.crz(np.pi / 1024, q[14], q[24])
        qc.crz(np.pi / 512, q[14], q[23])
        qc.crz(np.pi / 256, q[14], q[22])
        qc.crz(np.pi / 128, q[14], q[21])
        qc.crz(np.pi / 64, q[14], q[20])
        qc.crz(np.pi / 32, q[14], q[19])
        qc.crz(np.pi / 16, q[14], q[18])
        qc.crz(np.pi / 8, q[14], q[17])
        qc.crz(np.pi / 4, q[14], q[16])
        qc.crz(np.pi / 2, q[14], q[15])
        qc.h(q[14])
        qc.crz(np.pi / 2048, q[13], q[24])
        qc.crz(np.pi / 1024, q[13], q[23])
        qc.crz(np.pi / 512, q[13], q[22])
        qc.crz(np.pi / 256, q[13], q[21])
        qc.crz(np.pi / 128, q[13], q[20])
        qc.crz(np.pi / 64, q[13], q[19])
        qc.crz(np.pi / 32, q[13], q[18])
        qc.crz(np.pi / 16, q[13], q[17])
        qc.crz(np.pi / 8, q[13], q[16])
        qc.crz(np.pi / 4, q[13], q[15])
        qc.crz(np.pi / 2, q[13], q[14])
        qc.h(q[13])
        qc.crz(np.pi / 4096, q[12], q[24])
        qc.crz(np.pi / 2048, q[12], q[23])
        qc.crz(np.pi / 1024, q[12], q[22])
        qc.crz(np.pi / 512, q[12], q[21])
        qc.crz(np.pi / 256, q[12], q[20])
        qc.crz(np.pi / 128, q[12], q[19])
        qc.crz(np.pi / 64, q[12], q[18])
        qc.crz(np.pi / 32, q[12], q[17])
        qc.crz(np.pi / 16, q[12], q[16])
        qc.crz(np.pi / 8, q[12], q[15])
        qc.crz(np.pi / 4, q[12], q[14])
        qc.crz(np.pi / 2, q[12], q[13])
        qc.h(q[12])
        qc.crz(np.pi / 8192, q[11], q[24])
        qc.crz(np.pi / 4096, q[11], q[23])
        qc.crz(np.pi / 2048, q[11], q[22])
        qc.crz(np.pi / 1024, q[11], q[21])
        qc.crz(np.pi / 512, q[11], q[20])
        qc.crz(np.pi / 256, q[11], q[19])
        qc.crz(np.pi / 128, q[11], q[18])
        qc.crz(np.pi / 64, q[11], q[17])
        qc.crz(np.pi / 32, q[11], q[16])
        qc.crz(np.pi / 16, q[11], q[15])
        qc.crz(np.pi / 8, q[11], q[14])
        qc.crz(np.pi / 4, q[11], q[13])
        qc.crz(np.pi / 2, q[11], q[12])
        qc.h(q[11])
        qc.crz(np.pi / 16384, q[10], q[24])
        qc.crz(np.pi / 8192, q[10], q[23])
        qc.crz(np.pi / 4096, q[10], q[22])
        qc.crz(np.pi / 2048, q[10], q[21])
        qc.crz(np.pi / 1024, q[10], q[20])
        qc.crz(np.pi / 512, q[10], q[19])
        qc.crz(np.pi / 256, q[10], q[18])
        qc.crz(np.pi / 128, q[10], q[17])
        qc.crz(np.pi / 64, q[10], q[16])
        qc.crz(np.pi / 32, q[10], q[15])
        qc.crz(np.pi / 16, q[10], q[14])
        qc.crz(np.pi / 8, q[10], q[13])
        qc.crz(np.pi / 4, q[10], q[12])
        qc.crz(np.pi / 2, q[10], q[11])
        qc.h(q[10])
        qc.crz(np.pi / 32768, q[9], q[24])
        qc.crz(np.pi / 16384, q[9], q[23])
        qc.crz(np.pi / 8192, q[9], q[22])
        qc.crz(np.pi / 4096, q[9], q[21])
        qc.crz(np.pi / 2048, q[9], q[20])
        qc.crz(np.pi / 1024, q[9], q[19])
        qc.crz(np.pi / 512, q[9], q[18])
        qc.crz(np.pi / 256, q[9], q[17])
        qc.crz(np.pi / 128, q[9], q[16])
        qc.crz(np.pi / 64, q[9], q[15])
        qc.crz(np.pi / 32, q[9], q[14])
        qc.crz(np.pi / 16, q[9], q[13])
        qc.crz(np.pi / 8, q[9], q[12])
        qc.crz(np.pi / 4, q[9], q[11])
        qc.crz(np.pi / 2, q[9], q[10])
        qc.h(q[9])
        qc.crz(np.pi / 65536, q[8], q[24])
        qc.crz(np.pi / 32768, q[8], q[23])
        qc.crz(np.pi / 16384, q[8], q[22])
        qc.crz(np.pi / 8192, q[8], q[21])
        qc.crz(np.pi / 4096, q[8], q[20])
        qc.crz(np.pi / 2048, q[8], q[19])
        qc.crz(np.pi / 1024, q[8], q[18])
        qc.crz(np.pi / 512, q[8], q[17])
        qc.crz(np.pi / 256, q[8], q[16])
        qc.crz(np.pi / 128, q[8], q[15])
        qc.crz(np.pi / 64, q[8], q[14])
        qc.crz(np.pi / 32, q[8], q[13])
        qc.crz(np.pi / 16, q[8], q[12])
        qc.crz(np.pi / 8, q[8], q[11])
        qc.crz(np.pi / 4, q[8], q[10])
        qc.crz(np.pi / 2, q[8], q[9])
        qc.h(q[8])
        qc.crz(np.pi / 1.31072e5, q[7], q[24])
        qc.crz(np.pi / 65536, q[7], q[23])
        qc.crz(np.pi / 32768, q[7], q[22])
        qc.crz(np.pi / 16384, q[7], q[21])
        qc.crz(np.pi / 8192, q[7], q[20])
        qc.crz(np.pi / 4096, q[7], q[19])
        qc.crz(np.pi / 2048, q[7], q[18])
        qc.crz(np.pi / 1024, q[7], q[17])
        qc.crz(np.pi / 512, q[7], q[16])
        qc.crz(np.pi / 256, q[7], q[15])
        qc.crz(np.pi / 128, q[7], q[14])
        qc.crz(np.pi / 64, q[7], q[13])
        qc.crz(np.pi / 32, q[7], q[12])
        qc.crz(np.pi / 16, q[7], q[11])
        qc.crz(np.pi / 8, q[7], q[10])
        qc.crz(np.pi / 4, q[7], q[9])
        qc.crz(np.pi / 2, q[7], q[8])
        qc.h(q[7])
        qc.crz(np.pi / 2.62144e5, q[6], q[24])
        qc.crz(np.pi / 1.31072e5, q[6], q[23])
        qc.crz(np.pi / 65536, q[6], q[22])
        qc.crz(np.pi / 32768, q[6], q[21])
        qc.crz(np.pi / 16384, q[6], q[20])
        qc.crz(np.pi / 8192, q[6], q[19])
        qc.crz(np.pi / 4096, q[6], q[18])
        qc.crz(np.pi / 2048, q[6], q[17])
        qc.crz(np.pi / 1024, q[6], q[16])
        qc.crz(np.pi / 512, q[6], q[15])
        qc.crz(np.pi / 256, q[6], q[14])
        qc.crz(np.pi / 128, q[6], q[13])
        qc.crz(np.pi / 64, q[6], q[12])
        qc.crz(np.pi / 32, q[6], q[11])
        qc.crz(np.pi / 16, q[6], q[10])
        qc.crz(np.pi / 8, q[6], q[9])
        qc.crz(np.pi / 4, q[6], q[8])
        qc.crz(np.pi / 2, q[6], q[7])
        qc.h(q[6])
        qc.crz(np.pi / 5.24288e5, q[5], q[24])
        qc.crz(np.pi / 2.62144e5, q[5], q[23])
        qc.crz(np.pi / 1.31072e5, q[5], q[22])
        qc.crz(np.pi / 65536, q[5], q[21])
        qc.crz(np.pi / 32768, q[5], q[20])
        qc.crz(np.pi / 16384, q[5], q[19])
        qc.crz(np.pi / 8192, q[5], q[18])
        qc.crz(np.pi / 4096, q[5], q[17])
        qc.crz(np.pi / 2048, q[5], q[16])
        qc.crz(np.pi / 1024, q[5], q[15])
        qc.crz(np.pi / 512, q[5], q[14])
        qc.crz(np.pi / 256, q[5], q[13])
        qc.crz(np.pi / 128, q[5], q[12])
        qc.crz(np.pi / 64, q[5], q[11])
        qc.crz(np.pi / 32, q[5], q[10])
        qc.crz(np.pi / 16, q[5], q[9])
        qc.crz(np.pi / 8, q[5], q[8])
        qc.crz(np.pi / 4, q[5], q[7])
        qc.crz(np.pi / 2, q[5], q[6])
        qc.h(q[5])
        qc.crz(np.pi / 1.048576e6, q[4], q[24])
        qc.crz(np.pi / 5.24288e5, q[4], q[23])
        qc.crz(np.pi / 2.62144e5, q[4], q[22])
        qc.crz(np.pi / 1.31072e5, q[4], q[21])
        qc.crz(np.pi / 65536, q[4], q[20])
        qc.crz(np.pi / 32768, q[4], q[19])
        qc.crz(np.pi / 16384, q[4], q[18])
        qc.crz(np.pi / 8192, q[4], q[17])
        qc.crz(np.pi / 4096, q[4], q[16])
        qc.crz(np.pi / 2048, q[4], q[15])
        qc.crz(np.pi / 1024, q[4], q[14])
        qc.crz(np.pi / 512, q[4], q[13])
        qc.crz(np.pi / 256, q[4], q[12])
        qc.crz(np.pi / 128, q[4], q[11])
        qc.crz(np.pi / 64, q[4], q[10])
        qc.crz(np.pi / 32, q[4], q[9])
        qc.crz(np.pi / 16, q[4], q[8])
        qc.crz(np.pi / 8, q[4], q[7])
        qc.crz(np.pi / 4, q[4], q[6])
        qc.crz(np.pi / 2, q[4], q[5])
        qc.h(q[4])
        qc.crz(np.pi / 2.097152e6, q[3], q[24])
        qc.crz(np.pi / 1.048576e6, q[3], q[23])
        qc.crz(np.pi / 5.24288e5, q[3], q[22])
        qc.crz(np.pi / 2.62144e5, q[3], q[21])
        qc.crz(np.pi / 1.31072e5, q[3], q[20])
        qc.crz(np.pi / 65536, q[3], q[19])
        qc.crz(np.pi / 32768, q[3], q[18])
        qc.crz(np.pi / 16384, q[3], q[17])
        qc.crz(np.pi / 8192, q[3], q[16])
        qc.crz(np.pi / 4096, q[3], q[15])
        qc.crz(np.pi / 2048, q[3], q[14])
        qc.crz(np.pi / 1024, q[3], q[13])
        qc.crz(np.pi / 512, q[3], q[12])
        qc.crz(np.pi / 256, q[3], q[11])
        qc.crz(np.pi / 128, q[3], q[10])
        qc.crz(np.pi / 64, q[3], q[9])
        qc.crz(np.pi / 32, q[3], q[8])
        qc.crz(np.pi / 16, q[3], q[7])
        qc.crz(np.pi / 8, q[3], q[6])
        qc.crz(np.pi / 4, q[3], q[5])
        qc.crz(np.pi / 2, q[3], q[4])
        qc.h(q[3])
        qc.crz(np.pi / 4.194304e6, q[2], q[24])
        qc.crz(np.pi / 2.097152e6, q[2], q[23])
        qc.crz(np.pi / 1.048576e6, q[2], q[22])
        qc.crz(np.pi / 5.24288e5, q[2], q[21])
        qc.crz(np.pi / 2.62144e5, q[2], q[20])
        qc.crz(np.pi / 1.31072e5, q[2], q[19])
        qc.crz(np.pi / 65536, q[2], q[18])
        qc.crz(np.pi / 32768, q[2], q[17])
        qc.crz(np.pi / 16384, q[2], q[16])
        qc.crz(np.pi / 8192, q[2], q[15])
        qc.crz(np.pi / 4096, q[2], q[14])
        qc.crz(np.pi / 2048, q[2], q[13])
        qc.crz(np.pi / 1024, q[2], q[12])
        qc.crz(np.pi / 512, q[2], q[11])
        qc.crz(np.pi / 256, q[2], q[10])
        qc.crz(np.pi / 128, q[2], q[9])
        qc.crz(np.pi / 64, q[2], q[8])
        qc.crz(np.pi / 32, q[2], q[7])
        qc.crz(np.pi / 16, q[2], q[6])
        qc.crz(np.pi / 8, q[2], q[5])
        qc.crz(np.pi / 4, q[2], q[4])
        qc.crz(np.pi / 2, q[2], q[3])
        qc.h(q[2])
        qc.crz(np.pi / 8.388608e6, q[1], q[24])
        qc.crz(np.pi / 4.194304e6, q[1], q[23])
        qc.crz(np.pi / 2.097152e6, q[1], q[22])
        qc.crz(np.pi / 1.048576e6, q[1], q[21])
        qc.crz(np.pi / 5.24288e5, q[1], q[20])
        qc.crz(np.pi / 2.62144e5, q[1], q[19])
        qc.crz(np.pi / 1.31072e5, q[1], q[18])
        qc.crz(np.pi / 65536, q[1], q[17])
        qc.crz(np.pi / 32768, q[1], q[16])
        qc.crz(np.pi / 16384, q[1], q[15])
        qc.crz(np.pi / 8192, q[1], q[14])
        qc.crz(np.pi / 4096, q[1], q[13])
        qc.crz(np.pi / 2048, q[1], q[12])
        qc.crz(np.pi / 1024, q[1], q[11])
        qc.crz(np.pi / 512, q[1], q[10])
        qc.crz(np.pi / 256, q[1], q[9])
        qc.crz(np.pi / 128, q[1], q[8])
        qc.crz(np.pi / 64, q[1], q[7])
        qc.crz(np.pi / 32, q[1], q[6])
        qc.crz(np.pi / 16, q[1], q[5])
        qc.crz(np.pi / 8, q[1], q[4])
        qc.crz(np.pi / 4, q[1], q[3])
        qc.crz(np.pi / 2, q[1], q[2])
        qc.h(q[1])
        qc.crz(np.pi / 1.6777216e7, q[0], q[24])
        qc.crz(np.pi / 8.388608e6, q[0], q[23])
        qc.crz(np.pi / 4.194304e6, q[0], q[22])
        qc.crz(np.pi / 2.097152e6, q[0], q[21])
        qc.crz(np.pi / 1.048576e6, q[0], q[20])
        qc.crz(np.pi / 5.24288e5, q[0], q[19])
        qc.crz(np.pi / 2.62144e5, q[0], q[18])
        qc.crz(np.pi / 1.31072e5, q[0], q[17])
        qc.crz(np.pi / 65536, q[0], q[16])
        qc.crz(np.pi / 32768, q[0], q[15])
        qc.crz(np.pi / 16384, q[0], q[14])
        qc.crz(np.pi / 8192, q[0], q[13])
        qc.crz(np.pi / 4096, q[0], q[12])
        qc.crz(np.pi / 2048, q[0], q[11])
        qc.crz(np.pi / 1024, q[0], q[10])
        qc.crz(np.pi / 512, q[0], q[9])
        qc.crz(np.pi / 256, q[0], q[8])
        qc.crz(np.pi / 128, q[0], q[7])
        qc.crz(np.pi / 64, q[0], q[6])
        qc.crz(np.pi / 32, q[0], q[5])
        qc.crz(np.pi / 16, q[0], q[4])
        qc.crz(np.pi / 8, q[0], q[3])
        qc.crz(np.pi / 4, q[0], q[2])
        qc.crz(np.pi / 2, q[0], q[1])
        qc.h(q[0])
        qc.swap(q[0], q[24])
        qc.swap(q[1], q[23])
        qc.swap(q[2], q[22])
        qc.swap(q[3], q[21])
        qc.swap(q[4], q[20])
        qc.swap(q[5], q[19])
        qc.swap(q[6], q[18])
        qc.swap(q[7], q[17])
        qc.swap(q[8], q[16])
        qc.swap(q[9], q[15])
        qc.swap(q[10], q[14])
        qc.swap(q[11], q[13])
        qc.measure_all()
        return qc


if __name__ == "__main__":
    unittest.main()
