#initialization
import matplotlib.pyplot as plt
import numpy as np
import math

# importing Qiskit
from qiskit import transpile
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister

# import basic plot tools and circuits
from qiskit.visualization import plot_histogram
from qiskit.circuit.library import QFT

from qiskit.primitives import Sampler, Estimator

qpe = QuantumCircuit(4, 3)
qpe.x(3)
qpe.draw('mpl')

for qubit in range(3):
    qpe.h(qubit)
qpe.draw('mpl')

repetitions = 1
for counting_qubit in range(3):
    for i in range(repetitions):
        qpe.cp(math.pi/4, counting_qubit, 3); # controlled-T
    repetitions *= 2
qpe.draw('mpl')

qpe.barrier()
# Apply inverse QFT
qpe = qpe.compose(QFT(3, inverse=True), [0,1,2])
# Measure
qpe.barrier()
for n in range(3):
    qpe.measure(n,n)

qpe.draw('mpl')

sampler = Sampler()

result = sampler.run(qpe).result()
answer = result.quasi_dists[0]

plot_histogram(answer)

# Create and set up circuit
qpe2 = QuantumCircuit(4, 3)

# Apply H-Gates to counting qubits:
for qubit in range(3):
    qpe2.h(qubit)

# Prepare our eigenstate |psi>:
qpe2.x(3)

# Do the controlled-U operations:
angle = 2*math.pi/3
repetitions = 1
for counting_qubit in range(3):
    for i in range(repetitions):
        qpe2.cp(angle, counting_qubit, 3);
    repetitions *= 2

# Do the inverse QFT:
qpe2 = qpe2.compose(QFT(3, inverse=True), [0,1,2])

# Measure of course!
for n in range(3):
    qpe2.measure(n,n)

qpe2.draw('mpl')

# Let's see the results!
result = sampler.run(qpe2).result()
answer = result.quasi_dists[0]

plot_histogram(answer)

# Create and set up circuit
qpe3 = QuantumCircuit(6, 5)

# Apply H-Gates to counting qubits:
for qubit in range(5):
    qpe3.h(qubit)

# Prepare our eigenstate |psi>:
qpe3.x(5)

# Do the controlled-U operations:
angle = 2*math.pi/3
repetitions = 1
for counting_qubit in range(5):
    for i in range(repetitions):
        qpe3.cp(angle, counting_qubit, 5);
    repetitions *= 2

# Do the inverse QFT:
qpe3 = qpe3.compose(QFT(5, inverse=True), range(5))

# Measure of course!
qpe3.barrier()
for n in range(5):
    qpe3.measure(n,n)

qpe3.draw('mpl')

# Let's see the results!
result = sampler.run(qpe3).result()
answer = result.quasi_dists[0]
plot_histogram(answer)

qpe.draw('mpl')

from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
service.backends()

# Load our saved IBMQ accounts and get the least busy backend device with less than or equal to nqubits

service = QiskitRuntimeService()
backend = service.least_busy(operational=True,min_num_qubits=5)
print(backend)

# Run our circuit on the least busy backend. Monitor the execution of the job in the queue
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager


pm = generate_preset_pass_manager(optimization_level=3, backend=backend,seed_transpiler=11)

qc = pm.run(qpe)


qpe.draw('mpl',idle_wires=False)

# get the results from the computation
from qiskit.primitives import BackendSampler
sampler = BackendSampler(backend)

result = sampler.run(qpe).result()
answer = result.quasi_dists[0]

plot_histogram(answer)