from qiskit_alice_bob_provider.local.provider import AliceBobLocalProvider
from qiskit import QuantumCircuit, execute, transpile
from qiskit.visualization import plot_histogram
from qiskit.providers.fake_provider import FakeVigo
from qiskit_aer import AerSimulator
import matplotlib.pyplot as mp
from typing import Optional

provider = AliceBobLocalProvider()

provider.backends()

def build_bit_flip_circuit(delay_duration_us: float) -> QuantumCircuit:
    circ = QuantumCircuit(1, 1)
    circ.reset(0)
    circ.delay(delay_duration_us, 0, unit='us')
    circ.measure(0, 0)
    return circ

circ = build_bit_flip_circuit(30)
circ.draw('mpl')

counts = []
shots = 10000
sweep_range = range(1,5)

for nb_photons in range(1,5):
    backend = provider.get_backend('EMU:1Q:LESCANNE_2020', average_nb_photons=nb_photons)
    job = execute(circ, backend, shots=shots)
    counts.append(job.result().get_counts())

plot_histogram(counts, legend = ["average_nb_photons = %i" % i for i in sweep_range])

def build_phase_flip_circuit_cats(delay_duration_us: float) -> QuantumCircuit:
    circ = QuantumCircuit(1, 1)
    circ.initialize('+')
    circ.delay(delay_duration_us, 0, unit='us')
    circ.measure_x(0, 0)
    return circ

circ_fp = build_phase_flip_circuit_cats(0.1)
circ_fp.draw('mpl')

counts = []
shots = 10000
sweep_range = range(1,5)

for nb_photons in range(1,5):
    backend = provider.get_backend('EMU:1Q:LESCANNE_2020', average_nb_photons=nb_photons)
    job = execute(circ_fp, backend, shots=shots)
    counts.append(job.result().get_counts())

plot_histogram(counts, legend = ["average_nb_photons = %i" % i for i in sweep_range])

def build_phase_flip_circuit_transmons(delay_duration_us: float) -> QuantumCircuit:
    circ = QuantumCircuit(1, 1)
    circ.reset(0)
    circ.h(0)
    circ.delay(delay_duration_us, 0, unit='us')
    circ.h(0)
    circ.measure(0, 0)
    return circ

circ_transmons = build_phase_flip_circuit_transmons(0.1)
circ_transmons.draw('mpl')

def _measurement_cycle(distance: int) -> QuantumCircuit:
    cycle = QuantumCircuit(2 * distance - 1, distance - 1, name='cycle')
    for i in range(distance - 1):
        ancilla_idx = 2 * i + 1
        cycle.initialize('+', ancilla_idx)
    for i in range(distance - 1):
        ancilla_idx = 2 * i + 1
        cycle.cx(ancilla_idx, ancilla_idx + 1)
    for i in range(distance - 1):
        ancilla_idx = 2 * i + 1
        cycle.cx(ancilla_idx, ancilla_idx - 1)
    for i in range(distance - 1):
        ancilla_idx = 2 * i + 1
        cycle.measure_x(ancilla_idx, i)
    return cycle

def error_correction_cycle(distance: int, repetitions: int, initial_state: Optional[str] = None) -> QuantumCircuit:
    if initial_state is None:
        initial_state = distance * '+'
    circuit = QuantumCircuit(2 * distance - 1, distance + repetitions * (distance - 1))
    circuit.initialize(initial_state, range(0, distance * 2, 2))
    circuit.barrier()
    for cycle_idx in range(repetitions):
        first_bit = distance + cycle_idx * (distance - 1)
        circuit.append(_measurement_cycle(distance).to_instruction(), range(2 * distance - 1), range(first_bit, first_bit + distance - 1))
        circuit.barrier()
    for i in range(distance):
        circuit.measure_x(2 * i, i)
    return circuit

circ = error_correction_cycle(distance=3, repetitions=1)
backend = provider.get_backend('EMU:40Q:LOGICAL_TARGET')
transpile(circ, backend).draw('mpl')

from qiskit_alice_bob_provider.local.provider import AliceBobLocalProvider
from qiskit import QuantumCircuit, execute
from qiskit.visualization import plot_histogram

shots = 10000
provider = AliceBobLocalProvider()

backend = provider.get_backend('EMU:15Q:LOGICAL_EARLY')

circ = QuantumCircuit(2,2)
circ.reset(0)
circ.h(0)
circ.cx(0,1)
circ.measure(0,0)
circ.measure(1,1)

circ.draw('mpl')

job = execute(circ, backend, shots=shots)
plot_histogram(job.result().get_counts())

