import qiskit
qiskit.__qiskit_version__

from math import pi
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
%matplotlib inline

# importing Qiskit
from qiskit import BasicAer, IBMQ
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit import execute
from qiskit.tools.visualization import plot_histogram
from qiskit.tools.monitor import job_monitor

# Load saved IBMQ accounts
IBMQ.load_account()

# We first define controlled gates used in the IPEA
def cu1fixed(qProg, c, t, a):
    qProg.u1(-a, t)
    qProg.cx(c, t)
    qProg.u1(a, t)
    qProg.cx(c, t)

def cu5pi8(qProg, c, t):
    cu1fixed(qProg, c, t, -5.0*pi/8.0)

# We then prepare quantum and classical registers and the circuit
qr = QuantumRegister(2)
cr = ClassicalRegister(4)
circuitName="IPEAonSimulator"
ipeaCircuit = QuantumCircuit(qr, cr)

# Apply IPEA
ipeaCircuit.h(qr[0])
for i in range(8):
    cu5pi8(ipeaCircuit, qr[0], qr[1])
ipeaCircuit.h(qr[0])
ipeaCircuit.measure(qr[0], cr[0])

ipeaCircuit.reset(qr[0])

ipeaCircuit.h(qr[0])
for i in range(4):
    cu5pi8(ipeaCircuit, qr[0], qr[1])
ipeaCircuit.u1(-pi/2, qr[0]).c_if(cr, 1)
ipeaCircuit.h(qr[0])
ipeaCircuit.measure(qr[0], cr[1])

ipeaCircuit.reset(qr[0])

ipeaCircuit.h(qr[0])
for i in range(2):
    cu5pi8(ipeaCircuit, qr[0], qr[1])
ipeaCircuit.u1(-pi/4, qr[0]).c_if(cr, 1)
ipeaCircuit.u1(-pi/2, qr[0]).c_if(cr, 2)
ipeaCircuit.u1(-3*pi/4, qr[0]).c_if(cr, 3)
ipeaCircuit.h(qr[0])
ipeaCircuit.measure(qr[0], cr[2])

ipeaCircuit.reset(qr[0])

ipeaCircuit.h(qr[0])
cu5pi8(ipeaCircuit, qr[0], qr[1])
ipeaCircuit.u1(-pi/8, qr[0]).c_if(cr, 1)
ipeaCircuit.u1(-2*pi/8, qr[0]).c_if(cr, 2)
ipeaCircuit.u1(-3*pi/8, qr[0]).c_if(cr, 3)
ipeaCircuit.u1(-4*pi/8, qr[0]).c_if(cr, 4)
ipeaCircuit.u1(-5*pi/8, qr[0]).c_if(cr, 5)
ipeaCircuit.u1(-6*pi/8, qr[0]).c_if(cr, 6)
ipeaCircuit.u1(-7*pi/8, qr[0]).c_if(cr, 7)
ipeaCircuit.h(qr[0])
ipeaCircuit.measure(qr[0], cr[3])

backend = BasicAer.get_backend('qasm_simulator')
shots = 1000

results = execute(ipeaCircuit, backend=backend, shots=shots).result()
plot_histogram(results.get_counts())

# We then prepare quantum and classical registers and the circuit
qr = QuantumRegister(5)
cr = ClassicalRegister(5)
realStep1Circuit = QuantumCircuit(qr, cr)

# Apply IPEA
realStep1Circuit.h(qr[0])
for i in range(8):
    cu5pi8(realStep1Circuit, qr[0], qr[1])
realStep1Circuit.h(qr[0])
realStep1Circuit.measure(qr[0], cr[0])

#connect to remote API to be able to use remote simulators and real devices
print("Available backends:", [BasicAer.backends(), IBMQ.backends()])

backend = IBMQ.get_backend("ibmq_5_yorktown")
shots = 1000
   
job_exp1 = execute(realStep1Circuit, backend=backend, shots=shots)
job_monitor(job_exp1)

results1 = job_exp1.result()
plot_histogram(results1.get_counts())

realStep2Circuit = QuantumCircuit(qr, cr)

# Apply IPEA
realStep2Circuit.h(qr[0])
for i in range(4):
    cu5pi8(realStep2Circuit, qr[0], qr[1])
realStep2Circuit.u1(-pi/2, qr[0]) # Assuming the value of the measurement on Step 1
realStep2Circuit.h(qr[0])
realStep2Circuit.measure(qr[0], cr[0])

job_exp2 = execute(realStep2Circuit, backend=backend, shots=shots)
job_monitor(job_exp1)

results2 = job_exp2.result()
plot_histogram(results2.get_counts())

realStep3Circuit = QuantumCircuit(qr, cr)

# Apply IPEA
realStep3Circuit.h(qr[0])
for i in range(2):
    cu5pi8(realStep3Circuit, qr[0], qr[1])
realStep3Circuit.u1(-3*pi/4, qr[0]) # Assuming the value of the measurement on Step 1 and Step 2
realStep3Circuit.h(qr[0])
realStep3Circuit.measure(qr[0], cr[0])

job_exp3 = execute(realStep3Circuit, backend=backend, shots=shots)
job_monitor(job_exp3)

results3 = job_exp3.result()
plot_histogram(results3.get_counts())

realStep4Circuit = QuantumCircuit(qr, cr)

# Apply IPEA
realStep4Circuit.h(qr[0])
cu5pi8(realStep4Circuit, qr[0], qr[1])
realStep4Circuit.u1(-3*pi/8, qr[0]) # Assuming the value of the measurement on Step 1, 2, and 3
realStep4Circuit.h(qr[0])
realStep4Circuit.measure(qr[0], cr[0])
 
job_exp4 = execute(realStep4Circuit, backend=backend, shots=shots)
job_monitor(job_exp4)

results4 = job_exp4.result()
plot_histogram(results4.get_counts())