import warnings

warnings.filterwarnings("ignore", category=DeprecationWarning)

import qiskit as qk

qr0 = qk.QuantumRegister(1,name='qb')  # qb for "qubit", but the name is optional
cr0 = qk.ClassicalRegister(1,name='b') # b for "bit", but the name is optional
qc0 = qk.QuantumCircuit(qr0,cr0)


qc0.draw(output='mpl') # this is to visualize the circuit. Remove the output option for a different style.

from qiskit.tools.visualization import plot_bloch_vector
import math

theta = math.pi/2    # You can try to change the parameters theta and phi
phi = math.pi/4      # to see how the vector moves on the sphere
plot_bloch_vector([math.cos(phi)*math.sin(theta),math.sin(phi)*math.sin(theta),math.cos(theta)])  # Entries of the 
                                                                                                  # input vector are 
                                                                                                  # coordinates [x,y,z]

qc0.measure(qr0[0],cr0[0])

qc0.draw(output='mpl')

backend = qk.Aer.get_backend('qasm_simulator')
job = qk.execute(qc0, backend, shots=1024)
result = job.result()
counts = result.get_counts()
print(counts)

qc1 = qk.QuantumCircuit(qr0,cr0)
qc1.x(qr0[0]) # A X gate targeting the first (and only) qubit in register qr0
qc1.measure(qr0[0],cr0[0])

qc1.draw(output='mpl')

backend = qk.Aer.get_backend('qasm_simulator')
job1 = qk.execute(qc1, backend, shots=1024)
result1 = job1.result()
counts1 = result1.get_counts()
print(counts1)

from qiskit.tools.visualization import plot_bloch_multivector

vec_backend = qk.Aer.get_backend('statevector_simulator')
result_vec0 = qk.execute(qc0, vec_backend).result()
result_vec1 = qk.execute(qc1, vec_backend).result()
psi0 = result_vec0.get_statevector()
psi1 = result_vec1.get_statevector()

plot_bloch_multivector(psi0)

plot_bloch_multivector(psi1)

qc2 = qk.QuantumCircuit(qr0,cr0)
qc2.h(qr0[0])
qc2.measure(qr0[0],cr0[0])

qc2.draw(output='mpl')

job2 = qk.execute(qc2, backend, shots=1024)
result2 = job2.result()
counts2 = result2.get_counts()
print(counts2)

qc2_bis = qk.QuantumCircuit(qr0,cr0)
qc2_bis.h(qr0[0])

result_vec2 = qk.execute(qc2_bis, vec_backend).result()
psi2 = result_vec2.get_statevector()
plot_bloch_multivector(psi2)

qc3 = qk.QuantumCircuit(qr0,cr0)
qc3.h(qr0[0])
qc3.s(qr0[0]) # Use sdg instead of s for the adjoint
qc3.measure(qr0[0],cr0[0])

qc3.draw(output='mpl')

job3 = qk.execute(qc3, backend, shots=1024)
result3 = job3.result()
counts3 = result3.get_counts()
print(counts3)

qc3_bis = qk.QuantumCircuit(qr0,cr0)
qc3_bis.h(qr0[0])
qc3_bis.s(qr0[0])

result_vec3 = qk.execute(qc3_bis, vec_backend).result()
psi3 = result_vec3.get_statevector()
plot_bloch_multivector(psi3)

qc4 = qk.QuantumCircuit(qr0,cr0)
qc4.h(qr0[0])
qc4.t(qr0[0]) # Use tdg instead of t for the adjoint
qc4.measure(qr0[0],cr0[0])

qc4.draw(output='mpl')

job4 = qk.execute(qc4, backend, shots=1024)
result4 = job4.result()
counts4 = result4.get_counts()
print(counts4)

qc4_bis = qk.QuantumCircuit(qr0,cr0)
qc4_bis.h(qr0[0])
qc4_bis.t(qr0[0])

result_vec4 = qk.execute(qc4_bis, vec_backend).result()
psi4 = result_vec4.get_statevector()
plot_bloch_multivector(psi4)

lmbd = 1.2  # Change this value to rotate the output vector on the equator of the Bloch sphere
qc5 = qk.QuantumCircuit(qr0,cr0)
qc5.h(qr0[0])
qc5.u1(lmbd, qr0[0])

qc5.draw(output='mpl')

result_vec5 = qk.execute(qc5, vec_backend).result()
psi5 = result_vec5.get_statevector()
plot_bloch_multivector(psi5)

qc6 = qk.QuantumCircuit(qr0,cr0)
qc6.u2(0,math.pi, qr0[0])

result_vec6 = qk.execute(qc6, vec_backend).result()
psi6 = result_vec6.get_statevector()
plot_bloch_multivector(psi6)

theta = 0.5
phi = math.pi/4
lmb = math.pi/8

qc7 = qk.QuantumCircuit(qr0,cr0)
qc7.u3(theta,phi, lmb, qr0[0])

result_vec7 = qk.execute(qc7, vec_backend).result()
psi7 = result_vec7.get_statevector()
plot_bloch_multivector(psi7)

qr = qk.QuantumRegister(2,name='qr')  # we need a 2-qubit register now
cr = qk.ClassicalRegister(2,name='cr')
cnot_example = qk.QuantumCircuit(qr,cr)

cnot_example.x(qr[0])
cnot_example.cx(qr[0],qr[1]) # First entry is control, the second is the target
cnot_example.measure(qr[0],cr[0])
cnot_example.measure(qr[1],cr[1])

cnot_example.draw(output='mpl')

job_cnot = qk.execute(cnot_example, backend, shots=1024)
result_cnot = job_cnot.result()
counts_cnot = result_cnot.get_counts()
print(counts_cnot)

cnot_reversed = qk.QuantumCircuit(qr,cr)

cnot_reversed.x(qr[0])
# This part uses cx(qr[1],qr[0]) but is equivalent to cx(qr[0],qr[1])
cnot_reversed.h(qr[0])
cnot_reversed.h(qr[1])
cnot_reversed.cx(qr[1],qr[0])
cnot_reversed.h(qr[0])
cnot_reversed.h(qr[1])
#
cnot_reversed.measure(qr[0],cr[0])
cnot_reversed.measure(qr[1],cr[1])

cnot_reversed.draw(output='mpl')

job_cnot_rev = qk.execute(cnot_reversed, backend, shots=1024)
result_cnot_rev = job_cnot_rev.result()
counts_cnot_rev = result_cnot_rev.get_counts()
print(counts_cnot_rev)

bell_phi_p = qk.QuantumCircuit(qr,cr)

bell_phi_p.h(qr[0])
bell_phi_p.cx(qr[0],qr[1])
bell_phi_p.measure(qr[0],cr[0])
bell_phi_p.measure(qr[1],cr[1])

bell_phi_p.draw(output='mpl')

job_bell_phi_p = qk.execute(bell_phi_p, backend, shots=1024)
result_bell_phi_p = job_bell_phi_p.result()
counts_bell_phi_p = result_bell_phi_p.get_counts()
print(counts_bell_phi_p)

cz_example = qk.QuantumCircuit(qr)

cz_example.cz(qr[0],qr[1])

cz_example.draw(output='mpl')

cz_from_cnot = qk.QuantumCircuit(qr)

cz_from_cnot.h(qr[1])
cz_from_cnot.cx(qr[0],qr[1])
cz_from_cnot.h(qr[1])

cz_from_cnot.draw(output='mpl')

delta = 0.5
cphase_test = qk.QuantumCircuit(qr)

cphase_test.cu1(delta,qr[0],qr[1])

cphase_test.draw(output='mpl')

delta = 0.5
cphase_from_cnot = qk.QuantumCircuit(qr)

cphase_from_cnot.u1(delta/2,qr[1])
cphase_from_cnot.cx(qr[0],qr[1])
cphase_from_cnot.u1(-delta/2,qr[1])
cphase_from_cnot.cx(qr[0],qr[1])
cphase_from_cnot.u1(delta/2,qr[0])

cphase_from_cnot.draw(output='mpl')

swap_test = qk.QuantumCircuit(qr)

swap_test.swap(qr[0],qr[1])

swap_test.draw(output='mpl')

swap_from_cnot = qk.QuantumCircuit(qr)

swap_from_cnot.cx(qr[0],qr[1])
swap_from_cnot.cx(qr[1],qr[0])
swap_from_cnot.cx(qr[0],qr[1])

swap_from_cnot.draw(output='mpl')

qr_many = qk.QuantumRegister(5)
control_example = qk.QuantumCircuit(qr_many)

control_example.cy(qr_many[0],qr_many[1])
control_example.ch(qr_many[1],qr_many[2])
control_example.crz(0.2,qr_many[2],qr_many[3])
control_example.cu3(0.5, 0, 0, qr_many[3],qr_many[4])

control_example.draw(output='mpl')

qrthree = qk.QuantumRegister(3)
toffoli_example = qk.QuantumCircuit(qrthree)

toffoli_example.ccx(qrthree[0],qrthree[1],qrthree[2])

toffoli_example.draw(output='mpl')

toffoli_from_cnot = qk.QuantumCircuit(qrthree)

toffoli_from_cnot.h(qrthree[2])
toffoli_from_cnot.cx(qrthree[1],qrthree[2])
toffoli_from_cnot.tdg(qrthree[2])
toffoli_from_cnot.cx(qrthree[0],qrthree[2])
toffoli_from_cnot.t(qrthree[2])
toffoli_from_cnot.cx(qrthree[1],qrthree[2])
toffoli_from_cnot.tdg(qrthree[2])
toffoli_from_cnot.cx(qrthree[0],qrthree[2])
toffoli_from_cnot.tdg(qrthree[1])
toffoli_from_cnot.t(qrthree[2])
toffoli_from_cnot.h(qrthree[2])
toffoli_from_cnot.cx(qrthree[0],qrthree[1])
toffoli_from_cnot.tdg(qrthree[1])
toffoli_from_cnot.cx(qrthree[0],qrthree[1])
toffoli_from_cnot.s(qrthree[1])
toffoli_from_cnot.t(qrthree[0])

toffoli_from_cnot.draw(output='mpl')

crsingle = qk.ClassicalRegister(1)
deutsch = qk.QuantumCircuit(qr,crsingle)

deutsch.x(qr[1])
deutsch.h(qr[1])

deutsch.draw(output='mpl')

deutsch.h(qr[0])

deutsch.draw(output='mpl')

deutsch.cx(qr[0],qr[1])
deutsch.h(qr[0])
deutsch.measure(qr[0],crsingle[0])

deutsch.draw(output='mpl')

N = 4
qrQFT = qk.QuantumRegister(N,'qftr')
QFT = qk.QuantumCircuit(qrQFT)

for i in range(N):
    QFT.h(qrQFT[i])
    for k in range(i+1,N):
        l = k-i+1
        QFT.cu1(2*math.pi/(2**l),qrQFT[k],qrQFT[i])

QFT.draw(output='mpl')